I’m trying to get PDF from UIView with UILabel text mask.
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 200 ))
label.text = "Label Text"
label.font = UIFont.systemFont(ofSize: 25)
label.textAlignment = .center
label.textColor = UIColor.white
let overlayView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200 ))
overlayView.image = UIImage(named: "erasemask.png")
label.mask = overlayView
view_process.addSubview(label)
}
func exportAsPdfFromView(){
let pdfPageFrame = CGRect(x: 0, y: 0, width: view_process.bounds.size.width, height: view_process.bounds.size.height)
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pdfPageFrame, nil)
UIGraphicsBeginPDFPageWithInfo(pdfPageFrame, nil)
guard let pdfContext = UIGraphicsGetCurrentContext() else { return "" }
view_process.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
let path = self.saveViewPdf(data: pdfData)
print(path)
}
func saveViewPdf(data: NSMutableData) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("viewPdf.pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
but I do not get PDF with mask. I don’t want to convert UIView to UImage and then convert UImage to PDF. I want to editable PDF so don’t want to convert into UIImage.
Can anyone help me How to convert Masked UILabel to PDF ?
2
Answers
You have to draw text yourself in the pdf to make it editable.
I have slightly modified your code, and it works. You can simply copy/paste in a new app view controller to check the result.
Here is a screenshot of the document opened in AffinityDesigner. The mask is correctly applied as a layer mask, and the text is editable.
It needs some tweaking to respect exact layout.
EDITED
As a comparison, I have added the result by using the Apple
view.render
function, using code from the question ( with a blue background so we can see white text ). It clearly shows that this function does not support editable text and masking.It exports the document as a stack of flat images and extra – useless – groups.
So I guess the only solution to keep pdf entities types is to compose the document by rendering each object.
If you need to export complex forms, it must not be too hard to make a helper that crawls in the view hierarchy and render each object content.
If you need to also render pdf with interactive buttons, you will probably need to use Annotations( available in PDFKit ). By the way you can also create editable fields with annotations, but I’m not sure it supports masking.
LAST EDIT:
Since you use an external framework to render pdf ( PDFGenerator ), it is different. You can only override the
view.layer.render
function that is used by the framework and use thecontext.clip
function.To export ui components as editable, I think they must have no superview. As soon as there is a view hierarchy, a backing bitmap is created, and all render calls are made with this bitmap as parameter, and not the PDFContext that was used to call the first render.
That’s how PDFGenerator works, it crawls in the view hierarchy an render views by removing them from superview, render to the context, and move them back in hierarchy.
The big drawback of this is that it leads to bugs when the view is moved back in the hierarchy. Probably because constraints are lost, or some views like UIStackView behave differently. There is numerous opened issues around this on their github.
What I don’t really understand yet is why the label below is rendered as editable even in a view hierarchy. I guess it’s due to how the
render
function is done by Apple. Can’t go further on this right now..Custom Field Example:
It may need more work to respect exact field layout, but this is a basis for a view that is rendered as editable text. It gives the exact same result as in the first part of the answer.
So if you use this label instead of UILabel in the initial code of this question, it works.
this is my decision