An iOS PDF viewer and annotator written in Swift that can be embedded into any application.

Last update: Jun 27, 2022

UXM Token Field

CI Status Version Swift Carthage Compatible License Platform

Requirements

  • iOS 9 or above
  • Xcode 8 or above
  • Swift 3.0

Note

This project is still in early stages. Right now the PDF reader works both programmatically and through interface builder. This PDF reader supports interactive forms and provides methods for overlaying text, signature and checkbox elements onto the page, as well as rendering a PDF with the elements burned back onto the PDF. See the example project for how to implement.

Installation

CocoaPods

UXMPDFKit is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod "UXMPDFKit"

If you wish to use the Swift 2.3 version, use the following instead:

pod "UXMPDFKit", "~> 0.3.0"

Carthage

UXMPDFKit is also available through Carthage. To install just write into your Cartfile:

github "uxmstudio/UXMPDFKit"

Run carthage update to build the framework and drag the built UXMPDFKit.framework into your Xcode project.

Usage

Simple Usage

UXMPDFKit comes with a single page PDF reader with many features implemented right out of the box. Simply create a new PDFViewController, pass it a document and display it like any other view controller. It includes support for forms, a page scrubber and page scrolling.

Swift

let path = Bundle.main.path(forResource: "sample", ofType: "pdf")!
let document = try! PDFDocument(filePath: path, password: "password_if_needed")
let pdf = PDFViewController(document: document)

self.navigationController?.pushViewController(pdf, animated: true)

Objective-C

Although written in Swift, the core reader can be used in Objective-C.

NSError *error;
NSString *path = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"pdf"];
PDFDocument *document = [[PDFDocument alloc] initWithFilePath:path password:@"password_if_needed" error:&error];
PDFViewController *pdfVC = [[PDFViewController alloc] initWithDocument:document];

[self.navigationController pushViewController:pdfVC animated:true];

Single Page Collection View

This collection view renders a PDF in its entirety one page at a time in photo-slideshow style.

let collectionView = PDFSinglePageViewer(frame: self.view.bounds, document: self.document)
collectionView.singlePageDelegate = self

Its delegate methods are implemented as follows:

func singlePageViewer(collectionView: PDFSinglePageViewer, didDisplayPage page: Int)
func singlePageViewer(collectionView: PDFSinglePageViewer, loadedContent content: PDFPageContentView)
func singlePageViewer(collectionView: PDFSinglePageViewer, selectedAction action: PDFAction)

Forms

User-interactable forms are supported by UXMPDFKit, but only partially. Currently only PDF's versions 1.6 & 1.7 render correctly.

Form features implemented:

  • Signatures
  • Text Fields
  • Checkboxes
  • Radio Buttons
  • Choice Boxes

Form parsing and handling is taken care of by the PDFFormViewController. It takes a document, and then is passed a PDFPageContentView to render form elements onto.

let formController = PDFFormViewController(document: self.document)
formController.showForm(contentView)

PDF rewriting is not currently supported, but flattening inputed data onto the PDF is. To render the form information onto the document, call:

func renderFormOntoPDF() -> NSURL // Returns a temporary url
func save(url: NSURL) -> Bool // Writes 

Annotations

User annotations are supported at a basic level, however instead of being written onto the PDF, are burned on at the time of saving.

Current annotation types available:

  • Pen
  • Highlighter
  • Textbox

All annotations are stored in memory until being rendered back onto the PDF by the PDFRenderer.

To create a new annotation type, you must extend the following protocol:

public protocol PDFAnnotation {

    /// The page number the annotation is located on
    var page: Int? { get set }

    /// Unique identifier to be able to select annotation by
    var uuid: String { get }

    /// Boolean representing if the annotation has been saved
    var saved: Bool { get set }

    var delegate: PDFAnnotationEvent? { get set }

    /// Force implementations to have an init
    init()

    /// A function to return a view composed of the annotations properties
    func mutableView() -> UIView

    /// Set of handlers to pass touches to annotation
    func touchStarted(_ touch: UITouch, point: CGPoint)
    func touchMoved(_ touch: UITouch, point: CGPoint)
    func touchEnded(_ touch: UITouch, point: CGPoint)

    /// Method to save annotation locally
    func save()
    func drawInContext(_ context: CGContext)

    func didEnd()

    func encode(with aCoder: NSCoder)
}

An annotation should be an object that contains its position and value, not a view. Because annotations are written onto temporary objects, they should be created, not passed by reference each time mutableView() is called.

Additionally, it is recommended that the view passed by mutableView() extend ResizableView as this allows the annotation to be moved, resized and deleted individually.

In order for annotations to be able to be listed inside of the toolbar, they must also extend PDFAnnotationButtonable.

public protocol PDFAnnotationButtonable: PDFAnnotation {

    /// Name for UIBarButtonItem representation of annotation
    static var name: String? { get }

    /// Image for UIBarButtonItem representation of annotation 
    static var buttonImage: UIImage? { get }
}

Actions

Partial action support was added in version 0.3.0 and will be increased upon in future versions.

Currently supported actions:

  • External URL
  • Go To (internal jump to page index)
  • Remote Go To
  • Named
  • Launch
  • Javascript
  • Rich Media

Tapped actions are passed to your view controller by the PDFSinglePageViewer in its contentDelegate

Renderer

In order to perform write operations back onto a PDF in an efficient format, a renderer is used. Each type of form, annotation, etc that needs to be rendered back onto the PDF should extend the following protocol:

protocol PDFRenderer {
    func render(page: Int, context:CGContext, bounds: CGRect)
}

Controllers or objects that extend this protocol can then be passed to the PDFRenderer to be written onto a temporary document or saved permanently onto the document.

let renderer = PDFRenderController(document: self.document, controllers: [
    self.annotationController,
    self.formController
])
let pdf = renderer.renderOntoPDF()

Author

Chris Anderson:

License

UXMPDFKit is available under the MIT license. See the LICENSE file for more info.

GitHub

https://github.com/uxmstudio/UXMPDFKit
Comments
  • 1. Initialization from NSData is not supported

    At the moment the only initialization possible with the PDFDocument is from an URL string.

    I was wondering me if there's any plan to implement a version to support initialization from NSData.

    Reviewed by edias at 2017-01-01 13:21
  • 2. What is the proper way to check if a PDF is password protected?

    Previously, I used this piece of code to open a document and ask a password if the PDF appears to be password protected:

    func openDocument() {
      do {
        document = try PDFDocument(filePath: pdfFilePath, password: password)
      } catch let err {
        switch err as? CGPDFDocumentError {
        case .some(.passwordRequired):
          askPassword(firstTime: true)
        case .some(.couldNotUnlock):
          askPassword(firstTime: false)
        default:
          break
        }
        return
      }
      
      DispatchQueue.main.async {
        self.document?.currentPage = self.page
        self.openViewer()
      }
    }
    

    However, this doesn't work anymore as the exception thrown in CGPDFDocument.swift isn't forwarded. Right now I have implemented this workaround just below the catch above, but if feels dirty:

      if document?.documentRef == nil {
        askPassword(firstTime: true)
        return
      }
    

    What would be the proper way to check if a PDF is password-protected?

    Thanks, Rutger

    Reviewed by rbresjer at 2017-01-15 13:06
  • 3. Checkmarks Could Be Improved

    Couple suggestions for the checkboxes. Currently the checkboxes are invisible when not checked and even when checked they don't really look like checkboxes.

    What I suggest is to configure the buttons as toggle buttons. You'll need two images, one for the checked appearance and the other for the unchecked appearance. Set the checked image for the selected state and the unchecked image for the normal state. Add an action method for touchupinside and button.selected = !button.selected. When the selected state is set the checkmark image will appear.

    If you felt like it you can easily make a UIButton subclass with that behavior built in and just use that when you're building the checkmark button. This is probably best.

    Reviewed by phoney at 2016-11-10 21:41
  • 4. Toggle visibility of individual annotations for PDFViewController

    <!— Provide a general summary of the issue in the Title above —> I want to restrict the highlight and text annotations inside the PDFViewController while allowing the pen annotation.

    Expected Behaviour

    Add boolean values to controller the buttons for each annotation inside PDFViewController. i.e. instead of having a catch-all allowsAnnotations, have

    • allowHighlighterAnnotation
    • allowPenAnnotation
    • allowTextAnnotation

    These booleans would be used inside the function fileprivate func rightBarButtons() so that the buttons would not be appended in the navigation.

    Current Behaviour

    A single boolean value for allowsAnnotations for the PDFViewController

    Reviewed by bentacles at 2017-05-03 04:29
  • 5. Carthage build Error

    Hi,

    I've the following error building from Carthage: Dependency "UXMPDFKit" has no shared framework schemes for any of the platforms: iOS

    Thank you in advance, Omar.

    Reviewed by OmarCaf at 2017-01-11 16:10
  • 6. PDFDocument object conflicts with PDFKit.PDFDocument

    When I embed UXMPDFKit into my project, even without importing the framework in a particulat file, PDFDocument object inside library cause Xcode fails to import new PDFKit.PDFDocument and mark it as unavailable. I suggest renaming it to UXMPDFDocument to avoid ambiguity.

    Your Environment

    • iOS Version: 11.0
    • Xcode Version: 9.0
    • Swift Version: 4.0
    Reviewed by amosavian at 2017-09-24 09:16
  • 7. Extending the annotations

    Hi,

    I am trying to extend the annotations with one of my own. However, to do this i need to subclass pdfviewcontroller and annotationcontroller and point to the new annotationcontroller in the new pdfviewcontroller. This is not possible because of access levels:

    lazy var annotationController: PDFAnnotationController = PDFAnnotationController(document: self.document, delegate: self)

    both document and annotationController have access level internal. Do i need to find a new route or am i doing something wrong here? It's my first time coding for ios, so it could well be :)

    Thanks for your time

    Reviewed by jorritsmit at 2017-05-29 18:31
  • 8. WIP: Tap gestures

    This PR adds:

    • a delegate method that detects double taps on the pdf view.
    • a new variable pdfContentView (I'm not very happy with this name) that allows to retrieve the contentView of the pdf as UIView (keeping its inner actual type hidden). This is needed if the developer needs to capture events or interact only with the view that contains the actual pdf content, not the whole view.
    Reviewed by dmorn at 2017-05-25 12:18
  • 9. Crash when opening Full PDF Viewer in Example Project

    Hi! I've just build and run your Example Program with Xcode 8.0. It's OK for the first time after I click 'Show Full PDF Viewer', but the program crashed in a second when I back to ExampleViewController and click it again. The problem wasn't gone until I deleted the program in Simulator. And the problem comes again after I run the Example and click 'Show Full PDF Viewer'. Can you help to have a look please? Very thanks!

    'annotations = aDecoder.decodeObject(forKey: "annotations") as! [PDFAnnotation]' in PDFAnnotationStore
    
    Reviewed by kfindfly at 2017-02-17 07:16
  • 10. Crash when passing nil as a password on PDFDocument creation

    Hi and first of all thanks for the work!

    I encountered an issue while using the library : when I tried to create a PDFDocument instance for a file without a password, my first attempt was to call PDFDocument(filePath: path, password: nil), which caused my app to crash with mysterious error messages.

    I managed to fixed it by calling PDFDocument(filePath: path, password: "").

    This should be either stated clearly in the docs (maybe I've missed it?) or fixed in the code.

    Cheers!

    Reviewed by CKzu at 2017-01-03 17:49
  • 11. Open viewer at specific page

    Hi Chris,

    First of all: great work! Thanks for this great PDF viewer.

    If I set the PDFDocument to a specific page before initializing the PDFViewController with it, the page scrubber is shown at the correct page, but the document viewer isn't:

    let document = PDFDocument(filePath: pdfFilePath)
    document.currentPage = 33
    let pdfVc = PDFViewController(document: document)
    

    Is this an easy fix?

    Best regards, Rutger

    Reviewed by rbresjer at 2016-07-22 17:22
  • 12. I have pod install in objC project and create bridge header and import in my class like @import PDFKit and i have access frame work classes easily but i am not able to access class methods error as following as - "No visible @interface for 'PDFDocument' declares the selector 'initWithFilePath:password:error'" . NSError *error; NSString *path = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"pdf"]; PDFDocument *document = [[PDFDocument alloc] initWithFilePath:path password:@"password_if_needed" error:&error]; PDFViewController *pdfVC = [[PDFViewController alloc] initWithDocument:document]; [self.navigationController pushViewController:pdfVC animated:true];

    <!— Provide a general summary of the issue in the Title above —>

    Expected Behavior

    <!— If you’re describing a bug, tell us what should happen —> <!— If you’re suggesting a change/improvement, tell us how it should work —>

    Current Behavior

    <!— If describing a bug, tell us what happens instead of the expected behavior —> <!— If suggesting a change/improvement, explain the difference from current behavior —>

    Steps to Reproduce (for bugs)

    <!— Provide a set of steps to reproduce this bug. Include code if relevant —> 1. 2. 3. 4.

    Your Environment

    <!— Include as many relevant details about the environment you experienced the bug in —>

    • iOS Version:
    • Xcode Version:
    • Swift Version:
    Reviewed by RaviPatelCDN123 at 2019-11-13 09:06
  • 13. Layout issue when change device orientation

    In full pdf mode, when change to landscape, the screen becomes blank white. When scrolling the pdf shows but it also use the Vertical screen ratio. In storyboard mode, layout doesn't correct too.

    Reviewed by xinnai at 2019-11-07 01:36
  • 14. Issue While migrating to swift 4.2

    Using Current UXMPDFKit Version 0.7.2 for swift 3. But Cant Upgrade to swift 4.2 with version 0.7.3

    Bugs While Migrating to swift 4.2

    1. CocoaPods could not find compatible versions for pod "UXMPDFKit"
    2. CocoaPods could not find compatible versions for pod "UXMPDFKit" —> 1.CocoaPods could not find compatible versions for pod "UXMPDFKit": In Podfile: UXMPDFKit (~> 0.7.3)

    Steps to Reproduce (for bugs)

    1. Try to Update source repo that hosts the Podspec

    Your Environment

    • iOS Version: 11
    • Xcode Version: 10.1
    • Swift Version: 4.2
    Reviewed by MaliSharad at 2019-09-17 09:55
  • 15. Ho to change Pen, highliter and textfield color dynamic

    <!— Provide a general summary of the issue in the Title above —>

    Expected Behavior

    <!— If you’re describing a bug, tell us what should happen —> <!— If you’re suggesting a change/improvement, tell us how it should work —>

    Current Behavior

    <!— If describing a bug, tell us what happens instead of the expected behavior —> <!— If suggesting a change/improvement, explain the difference from current behavior —>

    Steps to Reproduce (for bugs)

    <!— Provide a set of steps to reproduce this bug. Include code if relevant —> 1. 2. 3. 4.

    Your Environment

    <!— Include as many relevant details about the environment you experienced the bug in —>

    • iOS Version:
    • Xcode Version:
    • Swift Version:
    Reviewed by Ronymark at 2019-09-16 10:38
Small utility to import PDF slides as vector images into Keynote for iOS.
Small utility to import PDF slides as vector images into Keynote for iOS.

Small utility to import PDF files into Keynote for iOS. This utility is especially helpful when presenting slideshows created by LaTeX

Jun 14, 2022
A simple generator of PDF written in Swift.

Features | Requirements | Installation | Usage | Communication | LICENSE PDFGenerator PDFGenerator is a simple PDF generator that generates with UIVie

May 31, 2022
SimplePDF is a wrapper of UIGraphics PDF context written in Swift.
SimplePDF is a wrapper of UIGraphics PDF context written in Swift.

SimplePDF is a wrapper of UIGraphics PDF context written in Swift. You can: add texts, images, spaces and lines, table set up page layout, adjust cont

Jun 7, 2022
Draw Week Time Table on PDF using PDFKit in iOS Swift
Draw Week Time Table on PDF using PDFKit in iOS Swift

DrawPDFTimeTable Draw Week Time Table on PDF using PDFKit in iOS Swift. Image Info This is the pdf of time table drawn using PDFKit in iOS Swift with

May 31, 2022
Mephisto - A command line tool to convert Comic Book Zip archives to PDF and share them over AirDrop
Mephisto - A command line tool to convert Comic Book Zip archives to PDF and share them over AirDrop

mephisto A command line tool written in Swift to convert Comic Book Zip archives

Feb 7, 2022
PDF Reader Core for iOS
PDF Reader Core for iOS

PDF Reader Core for iOS This project is no longer supported or maintained. It is only here for historical reasons. Please see the UXReader PDF Framewo

Jun 17, 2022
TPPDF is a simple-to-use PDF builder for iOS
TPPDF is a simple-to-use PDF builder for iOS

TPPDF is a fast PDF builder for iOS & macOS using simple commands to create advanced documents! Created and maintained by Philip Niedertscheider and a

Jun 10, 2022
PdfBuilder: a swift library made to make creation of the Pdf file from code simpler
PdfBuilder: a swift library made to make creation of the Pdf file from code simpler

PdfBuilder PdfBuilder is a swift library made to make creation of the Pdf file f

Mar 7, 2022
Swift package that uses WebKit to render PDF files from URLs

Swift package for generating a PDF file from a URL (rendered by WebKit)

Feb 25, 2022
PDF generator using UIViews or UIViews with an associated XIB

Description Create UIView objects using any method you like, including interface builder with Auto-layout and size classes enabled. Then generate a PD

Aug 28, 2020
Generate beautiful .pdf Files from xib

Description The Library generates a PDF directly from interface builder with Auto-layouted views! Swift Version of UIView_2_PDF. Installation Download

Sep 23, 2021
UIImage PDF extensions.

UIImagePlusPDF UIImage extensions to use PDF files. Using UIImagePlusPDF you can avoid a lot png images files (1x, 2x, 3x sizes) and simply replace ea

Jan 25, 2022
Estrutura Simples para Navegacao Web e Download PDF

Download-PDF-WebView Projeto desenvolvido em Swift com a função de criar uma estrutura simples para navegação Web em seu Aplicativo, permitindo a visu

Nov 30, 2021
📚 A Swift ePub reader and parser framework for iOS.
📚 A Swift ePub reader and parser framework for iOS.

FolioReaderKit is an ePub reader and parser framework for iOS written in Swift. Features ePub 2 and ePub 3 support Custom Fonts Custom Text Size Text

Jun 19, 2022
About PDFKit learning project on iOS 11, Like iBooks.app.
About PDFKit learning project on iOS 11, Like iBooks.app.

iBook About PDFKit learning project on iOS 11, Like iBooks.app. 书库 书库页面获取PDF相关数据, 可以通过KVC获取。 PDF书名 if let title = documentAttributes["Title"] as? Stri

Jun 23, 2022
A Static Library to be embedded on iOS applications to display pdf documents derived from Fast PDF

FastPdfKit This repository contains the FastPdfKit iOS library with some sample projects. FastPdfKit is a library that let you show pdf documents in i

Jun 17, 2022
JSONHelper - ✌ Convert anything into anything in one operation; JSON data into class instances, hex strings into UIColor/NSColor, y/n strings to booleans, arrays and dictionaries of these; anything you can make sense of!

JSONHelper Convert anything into anything in one operation; hex strings into UIColor/NSColor, JSON strings into class instances, y/n strings to boolea

May 30, 2022
DTPhotoViewerController - A fully customizable photo viewer ViewController to display single photo or collection of photos, inspired by Facebook photo viewer.
DTPhotoViewerController - A fully customizable photo viewer ViewController to display single photo or collection of photos, inspired by Facebook photo viewer.

DTPhotoViewerController Example Demo video: https://youtu.be/aTLx4M4zsKk DTPhotoViewerController is very simple to use, if you want to display only on

Jun 2, 2022
Starlight epub viewer - Epub viewer for flutter
Starlight epub viewer - Epub viewer for flutter

Starlight Epub Viewer starlight_epub_viewer is an epub ebook reader that encapsu

Jan 28, 2022
GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in iOS, macOS & tvOS apps.

GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in iOS, macOS & tvOS apps. It was written from scr

Jun 20, 2022