I would like to make the Text Widget PDFAnnotation readonly. I tried to set the isReadOnly flag to true, but it doesn't seem to make any difference. The user is still able to edit the annotation after tapping it.
Asked
Active
Viewed 2,348 times
4
-
Got the answer ? – Mohamed Raffi Jul 24 '18 at 17:17
-
No, but I've used a FreeText Annotation instead. And when I want to edit it, I'm placing a UITextView over the annotation. I believe this is exactly how Text Annotation work under the hood, because I'm getting the same UX. Also, I have more control over the editing and I'm able to immediately show the keyboard by selecting the text. Using Text annotation I was not able to make it 'first responder'. – crcalin Jul 25 '18 at 08:41
-
Apple's support for annotation flags is quite poor, we did write an overview here: https://pspdfkit.com/guides/web/current/annotations/annotation-flags/ – steipete Aug 14 '18 at 07:09
2 Answers
2
I have been working on this problem for a while now and I finally found something that works. The solution for me was to use a .widget
over .freeText
. This method keeps the text from being selected and modified after export. I should point out that PDFs are not infallible, decompilation is possible with any PDF but for the every day office worker this is a perfect solution.
//Don't use this - This is what most tutorials show
//Which can be easily changed after export
let annotation = PDFAnnotation(bounds: CGRect(x: 10 , y: 720 , width: 100, height: 50), forType: .freeText, withProperties: nil)
Use this - Swift 5
func addText(x: Int, y: Int, width: Int, height: Int, text: String, fontSize: CGFloat, centerText: Bool){
//I'm using a PDFView but, if you are not displaying the PDF in the app then just use
//let fileURL = Bundle.main.url(forResource: "MyPDF", withExtension: "pdf")!
//let pdfDocument = PDFDocument(url: fileURL)
//guard let document = pdfDocument else { return }
guard let document = pdfView.document else { return }
//I'm only using one page for my PDF but this is easy to change
let lastPage = document.page(at: document.pageCount - 1)
let annotation = PDFAnnotation(bounds: CGRect(x: x , y: y, width: width, height: height), forType: .widget, withProperties: nil)
//Don't use contents and caption
//annotation.contents = text
//annotation.caption = text
//Use this instead
annotation.widgetFieldType = .text
annotation.widgetStringValue = text
//Check if the text should be centered
if (centerText){ annotation.alignment = .center }
//I'm using a custom font
annotation.font = UIFont(name: "calibri", size: fontSize)
//You can use this instead
//annotation.font = UIFont.systemFont(ofSize: fontSize)
//Set the color
annotation.fontColor = .black
annotation.color = .clear
annotation.backgroundColor = .clear
//This is useless
annotation.isReadOnly = true
//Add the annotation to the last page
lastPage?.addAnnotation(annotation)
}

Greg432
- 530
- 4
- 25
0
It seems to be a bug/oversight that PDFKit doesn't honor the isReadOnly attribute on annotations. However I was able to work around this by adding a blank annotation over other annotations in the document. I added a makeReadOnly() extension to PDF document that does this for all annotations to make the whole document read only. Here's the code:
// A blank annotation that does nothing except serve to block user input
class BlockInputAnnotation: PDFAnnotation {
init(forBounds bounds: CGRect, withProperties properties: [AnyHashable : Any]?) {
super.init(bounds: bounds, forType: PDFAnnotationSubtype.stamp, withProperties: properties)
self.fieldName = "blockInput"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(with box: PDFDisplayBox, in context: CGContext) {
}
}
extension PDFDocument {
func makeReadOnly() {
for pageNumber in 0..<self.pageCount {
guard let page = self.page(at: pageNumber) else {
continue
}
for annotation in page.annotations {
annotation.isReadOnly = true // This _should_ be enough, but PDFKit doesn't recognize the isReadOnly attribute
// So we add a blank annotation on top of the annotation, and it will capture touch/mouse events
let blockAnnotation = BlockInputAnnotation(forBounds: annotation.bounds, withProperties: nil)
blockAnnotation.isReadOnly = true
page.addAnnotation(blockAnnotation)
}
}
}
}

Chris Garrett
- 4,824
- 1
- 34
- 49
-
1this will fix the problem only inside the app, If you try to save the PDF and then open it on any PDF editor or Preview app in MacOS, you will notice that you can move annotations and also you can delete it ! – Basel Feb 13 '19 at 19:51
-
In iOS13 the bug in `isReadOnly` attribute on annotations seems to be fixed – Giorgio Dec 16 '19 at 14:32