1

I just want to draw on a PDF file using PDFKit. This sounds simple but I'm having a lot of trouble. From the documentation, the ink annotations seem to be appropriate for this. Here's my code:

/// Adds a new annotation
func addAnnotation(color: UIColor, point: CGPoint) {
    currentPage = pdfView.page(for: point, nearest: false)

    // Here I convert the coordinates to the document and create a new annotation
    if currentPage != nil {
        let topRight = pdfView.convert(pdfView.frame.topRightCorner, to: currentPage!)
        newAnnotation = PDFAnnotation(bounds: CGRect(origin: .zero, size: CGSize(width: topRight.x, height: topRight.y)), forType: .ink, withProperties: nil)
        newAnnotation!.color = color
        currentPage!.addAnnotation(newAnnotation!)
    }
    else {
        newAnnotation = PDFAnnotation()
    }
}

/// Adds a new path, maybe a new annotation
func addPath(color: UIColor, point: CGPoint, lineWidth: CGFloat) {

    // Create annotation
    if newAnnotation == nil {
        addAnnotation(color: color, point: point)
    }

    guard currentPage != nil else { return }

    let convertedPoint = pdfView.convert(point, to: currentPage!)

    // Create initial path
    let path = UIBezierPath()
    path.lineWidth = 200
    path.move(to: convertedPoint)
    path.addLine(to: convertedPoint)
    newAnnotation!.add(path)
}

/// Updates the last drawn annotation
func updatePath(point: CGPoint) {
    if let annotation = newAnnotation, let page = currentPage {
        let convertedPoint = pdfView.convert(point, to: page)
        let lastPath = annotation.paths!.last!
        lastPath.addLine(to: convertedPoint)
        annotation.remove(lastPath)
        annotation.add(lastPath)
    }
}

My main problem is performance. I wrote all this code just to have a functional drawing program. What I understood in the process:

  • Grouping the paths in the annotations instead of having one annotation per path seems to be more efficient. So I added the addAnnotation() method, which sometimes creates a new annotation.
  • The 'bounds' property when creating an annotation plays a big part in performance. Setting this property to the page's bounds makes the program very slow.But the thing is, I don't know the bounds of the annotation before the user finish drawing...
  • I have a method touchMoved(), where I want to add a point the path. At first, I was just doing:

    if let annotation = newAnnotation, let page = currentPage {
        let convertedPoint = pdfView.convert(point, to: page)
        let lastPath = annotation.paths!.last!
        lastPath.addLine(to: convertedPoint)
    }
    

but the path was not updating, so I added the lines:

    annotation.remove(lastPath)
    annotation.add(lastPath)

This turned out to be really bad in term of performances (the path sometimes disappear, and reappear later).

I'm assuming there's a better way to do all of this, but I can't find any good example. If you have a working example of Ink annotations on PDFKit, that would be also great.

Side question: in my code I set the bezierPath's lineWidth to 200. This is because I want to change the lineWidth of the annotation, but changing the bezierPath's lineWidth doesn't seem to change anything. Any idea on that ?

Morpheus
  • 1,189
  • 2
  • 11
  • 33

1 Answers1

2

My observations are simiar to yours. I found that manipulating PDFAnnotation is troublesome, mostly because of a bug (PDFAnnotation with PDFAnnotationSubtype equal to .widget is not refreshing its appearance after adding it to PDFPage). Trick with deleting and readding them to PDFView is a nasty workaround.

Maybe it would be better to try with different approach? For example:

  1. Draw on a (transparent) CGLayer using CoreGraphics, on the top of PDFView.
  2. Transform drawing layer to UIImage.
  3. Add annotation with image to your PDFView. You can check Apple samples to find out how to do it. https://developer.apple.com/library/content/samplecode/PDFAnnotationEditor/Introduction/Intro.html#//apple_ref/doc/uid/DTS10004035
Rafał Rębacz
  • 486
  • 2
  • 11
  • This seems to be a good workaround, I'm gonna look into that. – Morpheus Feb 22 '18 at 18:51
  • This is indeed working. Do you have any idea for the lineWidth problem though ? This is even more important with this solution: I'm drawing on a layer with a certain width, but when I add it at the end as an annotation, the drawing always have a width of 1, and I can't change it. How can I change the width of the annotation, and is there any way I can convert the width in Core Graphics to the document, so that the drawing look the same when it's added ? Thanks – Morpheus Feb 22 '18 at 21:40
  • I didn't found any issues with annotation width. If you don't mind please add separate question for it. Source code would be also very helpful. – Rafał Rębacz Feb 22 '18 at 23:06