Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PdfKit highlight annotation

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?

like image 779
guco Avatar asked Sep 29 '17 11:09

guco


2 Answers

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.

like image 99
Johan de Klerk Avatar answered Nov 11 '22 19:11

Johan de Klerk


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)
    }
}
like image 2
npalatov Avatar answered Nov 11 '22 18:11

npalatov