PdfKit highlight annotation
Asked Answered
A

2

9

I'm trying to add highlight annotations to documents using PDFKit on iOS.

let highlight = PDFAnnotation(bounds: selection.bounds(for: page),
                              forType: PDFAnnotationSubtype.highlight,
                              withProperties: nil)

highlight.color = color

page.addAnnotation(highlight)
page.displaysAnnotations = true

When adding them using the code above, they appear as two differently shaped layers. When saving them to the PDF file and reopening it they display correctly.

In this screen capture

enter image description here

The top and bottom highlights have been added the same way using the snippet provided here. The top one has been saved to the pdf document and appears as expected when reopening it, the bottom one has just been added.

Does anyone know how to have them display correctly (i.e. like the top one) without resorting to saving and reopening the file?

Altimetry answered 29/9, 2017 at 11:1 Comment(5)
We have the exact same issueHinz
I logged a bug with Apple and I suggest you do the same openradar.appspot.com/34784917. You can log a bug at bugreport.apple.comHinz
I opened a bug through bugreport.apple.com as well, no answers so far.Altimetry
If you require a solution, we offer a commercial replacement for PDFKit that does not exhibit this bug. pspdfkit.com/blog/2017/introducing-pdfxkitArchiearchiepiscopacy
@Altimetry I have been trying to add similar highlights but can't seem to get the correct selection rect on text selection. Is there a way to get selection attributes via pdfkit after long pressing on some pdf text ?Lordosis
H
2

So this is a know bug in 10.13. There is a workaround by scrolling the page away and then back to the highlight

You can create the highlight using this code:

let page = self.pdfDocument?.page(at: 10)
let bounds = CGRect(x: 85.8660965, y: 786.8891167, width: 298.41, height: 12.1485)
let annotation = PDFAnnotation(bounds: bounds, forType: .highlight, withProperties: nil)
annotation.color = NSColor.blue
page?.addAnnotation(annotation)

Then you need to scroll away from the page and back to the highlight

func annotationScrollHack(page: PDFPage) {
    guard let pdfDocument = self.pdfDocument else { return }

    //When adding highlights to macOS 10.13 it seems like 2 highlights are added.
    //If you scroll to a different page and back the "extra" highlight is removed
    //This function scrolls to the first/last page in the book and then back to the current page
    //rdar://34784917
    let bookScrollView = self.pdfView.documentView?.enclosingScrollView
    let currentVisibleRect = bookScrollView?.contentView.documentVisibleRect
    if (0 ... 3).contains(pdfDocument.index(for: page)) {
        if self.pdfView.canGoToLastPage {
            self.pdfView.goToLastPage(self)
        }
    } else {
        if self.pdfView.canGoToFirstPage {
            self.pdfView.goToFirstPage(self)
        }
    }

    if let currentVisibleRect = currentVisibleRect {
        bookScrollView?.contentView.scroll(to: CGPoint(x: currentVisibleRect.origin.x, y: currentVisibleRect.origin.y))
    }
}

Response from Apple:

There is no workaround other than the “hack" they described: scrolling away then back is the best option. Changing zoom factor and reverting it might fix it in the same way, but not guaranteed.

Hinz answered 5/10, 2017 at 6:56 Comment(1)
This has been fixed in macOS 10.13.2Hinz
W
2

I've ended up with this hack method which takes into consideration all cases in my opinion. Hope that will help.

private func hackScroll(to page: PDFPage) {

    switch (pdfView.canGoToFirstPage(), pdfView.canGoToLastPage()) {
    case (true, false):
        pdfView.goToFirstPage(nil)
        pdfView.go(to: page)
    case (false, true):
        pdfView.goToLastPage(nil)
        pdfView.go(to: page)
    case (false, false):
        guard let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let file = "temp.pdf"

        /// Save to temp file
        let fileURL = dir.appendingPathComponent(file)
        pdfView.document?.write(to: fileURL)

        /// Read from temp file
        guard let document = PDFDocument(url: fileURL) else { return }
        pdfView.document = document
        pdfView.autoScales = true
    default:
        pdfView.goToFirstPage(nil)
        pdfView.go(to: page)
    }
}
Wilbur answered 18/10, 2017 at 13:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.