Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Artem Poluektov
Artem Poluektov

Posted on

     

iOS PDFKit tutorial: Text Annotations & more

This is the second article about Apple’s PDFkit featuring working with Text Annotations, document auto-saving and PencilKit.

  • First article is about PDFKit basics & Ink annotations
  • Third article is about creating PDF document on device and inserting/removing pages

PencilKit

We tried to implementPencilKit support in our app right after iOS 13 release. We even created a ticket to Apple Technical Support asking is there any easy way to do so. Short answer isNO.
You just can't usePencilKit together withPDFKit like how it works in native iOS markup screens.

Apple Technical Support answer:

The PencilKit team recommends developers put a PKCanvasView over each PDFPage. Signatures are a little different - you'd probably need to grab the PKDrawing from the PKCanvasView and then render the PKDrawing as an image inside of a PDFPage as you would a watermark.

Proposed solution seems to be impossible to implement (addingPKCanvasView toPDFPage). Second part (about grabbingPKDrawing) seems to be not the right way for our task too because of requirement to zoom page and erase previously added annotations. So, I feel that our solution from the first part of this tutorial is still the right one.

PKToolPicker seems not to be the right fit as well. It looks much better than out instruments view, but is completely not customizable. For example, in iOS 13 it features ruler, and if we don't need it in our app, we're still unable to remove it from ToolPicker. Hope, Apple would add some ways for customization in future releases.


Text annotations

Text annotations seems to be easier than drawing (Ink). However due to lack of documentation and sample code (again!) it wasn't an easy task.

So, let's assume we need to add some "Hello, world!" text to some place on a document's last page. To do so, write the code below (in your Drawing View Controller, for this example):

func addDateAnnotation() {  guard let document = pdfView.document else { return }  let lastPage = document.page(at: document.pageCount - 1)  let annotation = PDFAnnotation(bounds: CGRect(x: 100, y: 100, width: 100, height: 20), forType: .freeText, withProperties: nil)  annotation.contents = "Hello, world!"  annotation.font = UIFont.systemFont(ofSize: 15.0)  annotation.fontColor = .blue  annotation.color = .clear  lastPage?.addAnnotation(annotation)}
Enter fullscreen modeExit fullscreen mode

First, you need a page where you want to add annotation. Then you need to set following properties:

  • contents: text to display,
  • font: font,
  • fontColor: foreground color,
  • color: background color.

That's it. Just don't forget to save your document.


Annotation types

In one of our tasks we needed to iterate through all annotations array to remove annotation of the specific type. We found that callingPDFAnnotationSubtype.freeText andannotation.type would actually return different results!

PDFAnnotationSubtype.freeText // "/freeText"annotation.type // "FreeText"
Enter fullscreen modeExit fullscreen mode

So, to filter annotations of the specific type we had to call:

allPageAnnotations.filter { $0.type == "FreeText" }
Enter fullscreen modeExit fullscreen mode

instead of

allPageAnnotations.filter { $0.type == PDFAnnotationSubtype.freeText }
Enter fullscreen modeExit fullscreen mode

Next & Previous buttons

Implementing next & previous buttons [which are very useful for your users] is very easy. Just add those buttons in your Storyboard and call one of those methods:

pdfView.goToPreviousPage(nil)// orpdfView.goToNextPage(nil)
Enter fullscreen modeExit fullscreen mode

Auto-saving the document

Due to our long history with crashes we decided to implement auto-saving feature. We wanted to save PDFDocument after each successfully drawn annotation and used this code:

pdfDocument.write(to: url)
Enter fullscreen modeExit fullscreen mode

However, with larger documents this code caused UI freezes, so we tried to do it in background:

DispatchQueue.global(qos: .background).async {  pdfDocument.write(to: url)}
Enter fullscreen modeExit fullscreen mode

Which caused crashes when document's content changed during saving.
Our final solution was to usePDFDocument methoddataRepresentation combined with simpleTimer:

if let data = pdfDocument.dataRepresentation() {  try? data.write(to: url)}
Enter fullscreen modeExit fullscreen mode

This solution didn't cause crashes, but madePDFView blink on this call. The only working solution we found was:

  • create a copy ofPDFDocument ,
  • apply all changes (adding/removing annotations) to visible document inPDFView and to copy, only add completed annotations due to performance,
  • save copy each 30 seconds (for example),
  • track all changes during saving: you cannot apply changes during save, so need to store changes history in memory during saving, which may take some time with a bigger files.

Useful links
You would find some initial information about PDFKit in this WWDC video:

Here you'll find Apple's sample code of advanced drawing with Apple Pencil. Not sure it would work really great with PDFs due to performance issues.

If you're looking for any alternative solution, check one of these frameworks. I haven't found any free or open-source solutions, and licenses for those in the list are pretty expensive ($500-$1K+).
PSPDFKit. Features drop-in replacement APIs for Apple's

  • PDFKit,
  • Foxit,
  • PDFTron.

Top comments(1)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
kanojiya_deepak_14f75c401 profile image
Kanojiya Deepak
  • Joined

` footerAnnotation.contents = watermarkText.dropLast(2) + "**"
footerAnnotation.font = UIFont.systemFont(ofSize: 20)
footerAnnotation.color = .clear
footerAnnotation.fontColor = UIColor.darkGray
.withAlphaComponent(0.5)

why this not work UIColor.darkGray
.withAlphaComponent(0.5)

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Joined

More fromArtem Poluektov

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp