Migrating from Apple PDFKit

Apple’s PDFKit provides a great starting point for integrating PDF support into your iOS app. It’s a system library, so it’s easy to integrate.

PSPDFKit, on the other hand, is a cross-platform PDF framework with more advanced features and fine-grained control over various aspects of PDF handling. It also includes a lot of customization options:

  • Advanced and native UI and UX, with support for most PDF features

  • Support for all annotations defined in the PDF specification

  • Importing and exporting annotations in JSON and XFDF formats

  • Accessing files embedded in documents

  • Adding watermarks to documents

  • Programmatic form filling

  • Indexed full-text search (with near-instant search results)

  • Loading of documents from custom sources with on-the-fly decryption

  • Advanced, customizable rendering, including CMYK color space support

  • Custom bookmark implementation (bookmarks are not part of the PDF spec)

  • Available on multiple platforms with excellent interoperability

  • Constantly improving with new features

  • First-class support directly from our engineers

To simplify migrating a codebase from PDFKit to PSPDFKit as much as possible, we provide a wrapper called PDFXKit. It’s a drop-in replacement with little or no changes required, and it allows you to program against the PDFKit API while using PSPDFKit under the hood. See the Easy Transition with PDFXKit section below for more information.

Introduction

The PSPDFKit API can be overwhelming at first, especially when coming from Apple PDFKit. But once you understand the basic concepts, it’s straightforward. We traded a bit of simplicity for flexibility and performance, and we achieve this by using a couple of techniques and patterns.

For example, the responsibility for providing, parsing, and managing various PDF objects and concepts is split into individual classes. These are called ...Provider, ...Parser, and ...Manager. We expose the classes publicly to give you hooks for customization, advanced control, and performance optimization.

Overview

The only UI classes provided by Apple’s PDFKit are PDFView and PDFThumbnailView. All remaining classes in Apple’s PDFKit are what Apple calls utility classes. Let’s take a look at these and see how they relate to PSPDFKit.

The following table shows an overview of Apple’s PDFKit classes that have a corresponding class in PSPDFKit:

The PDFPage class doesn’t have a corresponding class in PSPDFKit; the concept of a page is supported mainly via page indexes, as described in more detail in the Page Handling section.

The PDFSelection class doesn’t have a corresponding class in PSPDFKit. While PDFSelection is generic in Apple’s PDFKit, covering multiple use cases, PSPDFKit offers more dedicated objects for each use case. Text selected by a user is a UI concept. For more information, see the Text Handling section.

Document Handling

The PDFDocument class in Apple PDFKit represents a single PDF document either stored on disk as a file or loaded via a Data object. This class corresponds to Document in PSPDFKit.

A Document consists of one or more PDFDocumentProviders. You can think of one provider as corresponding to a single file on disk. This allows you to treat multiple PDF files as a single document in cases where you need to. Many customers use this feature to split large documents up into individual files — for example, to download each part individually on demand.

Page Handling

As noted above, PSPDFKit doesn’t have a corresponding class for PDFPage. Anything related to a page is accessed via the document or a related object by passing a page index. For example, you’d use Document’s annotationsForPage(at:type:) to get annotations for a specific page. Page indexed access allows PSPDFKit to better optimize for performance.

The main object for manipulating pages of a document is PDFDocumentEditor and its related classes (see the Document Editor announcement blog post). It allows you to:

  • Add pages

  • Remove pages

  • Duplicate pages

  • Rotate pages

  • Extract pages (saving as a new PDF document)

Please consult the Document Editing guide, particularly the section on Programmatic Access.

Text Handling

Other than selecting text at the UI level, extracting text and inspecting blocks of text are probably the two main use cases of PDFSelection in Apple PDFKit.

In PSPDFKit, both of these use cases are covered by TextParser, which you can access via the textParserForPage(at:) method of Document. It offers a simple API to get text, glyphs (Glyph), words (Word), text blocks (TextBlock), and even images (ImageInfo).

In a PDF, text usually corresponds to glyphs positioned at an absolute location on a specific page. PSPDFKit uses advanced heuristics to group these glyphs into meaningful words and text blocks.

Outline

The PDFOutline class encapsulates the outline concept of a PDF document. PSPDFKit has a corresponding class named OutlineElement, which works similarly to PDFOutline. You can access the outline via the outline property on Document:

let document = /* Create a PSPDFDocument  */
let rootOutlineElement = document.outline
PSPDFDocument *document = /* Create a PSPDFDocument  */;
PSPDFOutlineElement* rootOutlineElement = document.outline;

With the root outline element, you can walk the outline tree, get information, and perform operations on the outline elements, similar to how you would with PDFOutline. For more information, please consult the API reference.

Annotations

Apple PDFKit provides a single PDFAnnotation class, together with a small PDFBorder utility class representing annotations and their borders. PSPDFKit supports all annotations as defined by the PDF specification with a rich and flexible API. We have an extensive guide covering all aspects of annotations.

PSPDFKit offers two search options:

  • Regular search, which is equivalent to Apple PDFKit and easy to use

  • Indexed full-text search, which is blazing fast but requires more setup

To perform a regular search for a document, create an instance of TextSearch, passing in the loaded Document via its initializer. Searching can be triggered via calling search(for:), which will start a search in a background queue. Implement TextSearchDelegate on the receiving object and set the text search object’s delegate to your object to be notified of search result updates.

To learn more about our blazingly fast indexed full-text search, please take a look at the Indexed Full-Text Search guide.

Rendering

Apple PDFKit lets you render a PDFPage into a specific context using the drawWithBox:toContext: method. Similarly, the easiest way to render a page with PSPDFKit is to use one of the following Document methods:

// `Document`
func imageForPage(at pageIndex: PageIndex, size: CGSize, clippedTo clipRect: CGRect, annotations: [Annotation]?, options: RenderOptions?) throws -> UIImage
func renderPage(at pageIndex: PageIndex, context: CGContext, size: CGSize, clippedTo clipRect: CGRect, annotations: [Annotation]?, options: RenderOptions?) throws
// `PSPDFDocument`
- (nullable UIImage *)imageForPageAtIndex:(PSPDFPageIndex)pageIndex size:(CGSize)size clippedToRect:(CGRect)clipRect annotations:(nullable NSArray<PSPDFAnnotation *> *)annotations options:(nullable PSPDFRenderOptions *)options error:(NSError *_Nullable *_Nullable)error;
- (BOOL)renderPageAtIndex:(PSPDFPageIndex)pageIndex context:(nonnull CGContextRef)context size:(CGSize)size clippedToRect:(CGRect)clipRect annotations:(nullable NSArray<PSPDFAnnotation *> *)annotations options:(nullable PSPDFRenderOptions *)options error:(NSError *_Nullable *_Nullable)error;

Beyond this basic rendering support, PSPDFKit offers an advanced, asynchronous rendering pipeline that gives you control over various aspects of the rendering result and performance. You first create a RenderRequest, which specifies what and how to render the page. You use that render request to create a RenderTask, set yourself as a delegate on that, and schedule it in a RenderQueue. Once finished, the render task will notify the delegate and pass it the resulting image. See the Rendering PDF Pages guide for more details.

For more information on advanced rendering, please consult the API reference for these classes, along with our PSPDFKit Catalog example project. See the Example Projects guide for more details.

Basic User Interface

As of iOS 11, PDFKit provides two UI classes for displaying and browsing PDF files: PDFView and PDFThumbnailView.

PDFView is the main UI class that allows you to display a PDF document using different display modes and options to tweak the appearance. The corresponding class in PSPDFKit is the PDFViewController.

PDFThumbnailView is an accessory control for a PDFView showing a strip of thumbnails for each page of the currently displayed PDF document. The corresponding class in PSPDFKit is the ScrubberBar.

Unlike PDFView, the PDFViewController is meant to be a drop-in solution with very little code or UI required from your side. All you have to do is create a PDFViewController and present it as is. Everything else is handled for you automatically by default – including displaying the ScrubberBar.

The following code snippet demonstrates how to display a PDF using PDFViewController and a thumbnail bar matching the one from PDFKit:

import PSPDFKit

// Load the document.
let documentURL = Bundle.main.url(forResource: "Document", withExtension: "pdf")!
let document = Document(url: documentURL)

// Create a configuration object and tweak the thumbnail bar, which will use
// the appropriate view — in this case, the `ScrubberBar`.
let configuration = PDFConfiguration {
    $0.thumbnailBarMode = .scrubberBar
    // Add your configuration options here.
}

// Put the PDF view controller inside a navigation controller to
// give it a navigation bar for various PDF-related controls.
let pdfViewController = PDFViewController(document: document, configuration: configuration)
let navigationController = UINavigationController(rootViewController: pdfViewController)

present(navigationController, animated: true)
#import <PSPDFKit/PSPDFKit.h>

// Load the document.
NSURL *documentURL = [NSBundle.mainBundle URLForResource:@"Document" withExtension:@"pdf"];
PSPDFDocument *document = [[PSPDFDocument alloc] initWithURL:documentURL];

// Create a configuration object and tweak the thumbnail bar, which will use
// the appropriate view — in this case, the `PSPDFScrubberBar`.
PSPDFConfiguration *configuration = [PSPDFConfiguration configurationWithBuilder:^(PSPDFConfigurationBuilder *builder) {
    builder.thumbnailBarMode = PSPDFThumbnailBarModeScrubberBar;
    // Add your configuration options here.
}];

// Put the PDF view controller inside a navigation controller to
// give it a navigation bar for various PDF-related controls.
PSPDFViewController *pdfViewController = [[PSPDFViewController alloc] initWithDocument:document configuration:configuration];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:pdfViewController];

[self presentViewController:navigationController animated:YES completion:NULL];

The result should look something like this:

PDF page coordinates

Advanced User Interface

Apart from basic support for displaying and browsing PDFs with the two PDFKit classes above, everything else needs to be implemented from scratch with PDFKit. PSPDFKit, on the other hand, provides everything you need to handle PDFs in your app, ready to be used out of the box.

When presented within a navigation controller, the PDFViewController puts a couple of buttons into the navigation bar by default, giving you access to the following features:

PSPDFKit offers more UI components not directly accessible via the PDFViewController, including the PDFDocumentPickerController and the PDFTabbedViewController. All of these components are designed to be easy to integrate and customize so as to perfectly blend into your app. To learn more, please take a look at our Customizing the Interface section of the guides, as well as our extensive documentation and API reference.

Easy Transition with PDFXKit

If your app is already using PDFKit, migrating the full codebase to PSPDFKit can be a major undertaking and a dealbreaker for many developers. In this case, we encourage you to give PDFXKit a try.

PDFXKit is a drop-in replacement that gives you the same APIs as PDFKit while using PSPDFKit under the hood, with only a few tweaks required. PDFXKit gives you full access to the underlying PSPDFKit, allowing you take advantage of all PSPDFKit features, components, and tools if and when you need them.

PDFXKit is open source. Please visit the project page on GitHub for more info.

Conclusion

If you have experience with Apple PDFKit, by now you should have a rough idea of how to translate that to PSPDFKit. If you have an existing codebase using PDFKit, PDFXKit makes the transition to PSPDFKit a breeze.

While PDFKit is a great starting point for adding basic PDF support to your app, PSPDFKit goes much further, offering you a cross-platform drop-in solution with many UI components, advanced PDF features, and first-class support directly from the developers.

Please consult our website, our guides, and our API reference for additional information about various parts of PSPDFKit.