iOS PDFKit: creating PDF document in Swift, inserting/deleting pages

artem_poluektov

Artem Poluektov

Posted on March 19, 2023

iOS PDFKit: creating PDF document in Swift, inserting/deleting pages

This is the third article about Apple’s PDFkit featuring in-code document creation and pages operations.

  • First article is about PDFKit basics & Ink annotations
  • Second is about PencilKit, Text annotations & auto-saving

Create PDF Document using Swift

In case you need to create a new PDF file on iOS device you won’t actually need to use PDFKit at all. There are few simple UIKit methods for that.

First, you need to create UIGraphicsPDFRendererFormat object to provide PDF document metadata such as author, etc.

let format = UIGraphicsPDFRendererFormat()
let metaData = [
    kCGPDFContextTitle: "Hello, World!",
    kCGPDFContextAuthor: "John Doe"
  ]
format.documentInfo = metaData as [String: Any]
Enter fullscreen mode Exit fullscreen mode

You’ll find a full list of available metadata parameters in CoreGraphics framework reference documentation, just start typing kCGPDF in your code in Xcode.

Second, we need to calculate PDF page dimensions. PDF documents use a default resolution of 72 DPI. Page dimensions would be:

// US Letter
Width: 8.5 inches * 72 DPI = 612 points
Height: 11 inches * 72 DPI = 792 points
// A4 would be [W x H] 595 x 842 points
Enter fullscreen mode Exit fullscreen mode

After doing this math, we need to instantiate UIGraphicsPDFRenderer object, which is responsible of document rendering.

let pageRect = CGRect(x: 0, y: 0, width: 595, height: 842)
let renderer = UIGraphicsPDFRenderer(bounds: pageRect,
                                     format: format)
Enter fullscreen mode Exit fullscreen mode

Third, to start drawing just call .pdfData method of your renderer:

let data = renderer.pdfData { (context) in
// Perform your drawing here
}
Enter fullscreen mode Exit fullscreen mode

You could call every drawing method of CoreGraphics framework here. But, first you need to create new PDF page by calling context.beginPage(). Call this code every time you need to start new page.
To draw a simple “Hello, world!” text use this code example:

let data = renderer.pdfData { (context) in
  context.beginPage()

  let paragraphStyle = NSMutableParagraphStyle()
  paragraphStyle.alignment = .center
  let attributes = [
    NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14),
    NSAttributedString.Key.paragraphStyle: paragraphStyle
  ]
  let text = "Hello, World!"
  let textRect = CGRect(x: 100, // left margin
                        y: 100, // top margin
                    width: 200,
                   height: 20)

  text.draw(in: textRect, withAttributes: attributes)
}
Enter fullscreen mode Exit fullscreen mode

What’s just happened?

  • We started new PDF page.
  • Created new NSParagraphStyle object to add .center alignment to our text.
  • Created attributes dictionary containing font and paragraph style.
  • Created text String.
  • Created textRect struct describing specific rect where our text would be drawn.
  • Called .draw method of string object.

That’s it. Easy, right? Just provide your own attributes like color, font, etc.

Finally, we must save out PDF context to file on device. As rendered would return Data object, we have 2 ways of saving our document:

  • Initializing PDFKit's PDFDocument(data:) object and writing it to file
let pdfDocument = PDFDocument(data: data)
let path = PATH_TO_DESIRED_FILE
pdfDocument.write(to: path)
Enter fullscreen mode Exit fullscreen mode
  • Using UIGraphicsPDFRendered's method writePDF instead of pdfData in third step. Let's replace
let data = renderer.pdfData { (context) in
Enter fullscreen mode Exit fullscreen mode

with

let url = URL_TO_DESIRED_FILE
try? rendered.writePDF(to: url) { (context) in
  ...
}
Enter fullscreen mode Exit fullscreen mode

You must add try? call because writing operation is throwable.


Insert page to PDF document

To add or remove pages to/from PDF document we need to use Apple’s PDFKit methods.
First, you need to initialize 2 PDF documents. One where the page would be inserted, and another from which we’ll take the page to insert.

let firstPDFDocument = PDFDocument(url: URL_TO_YOUR_FIRST_DOC)
let secondPDFDocument = PDFDocument(url: URL_TO_YOUR_SECOND_DOC)
Enter fullscreen mode Exit fullscreen mode

Second, locate the page you want to insert and insert it at desired location:

// let's assume we want to insert 5th page of 2nd doc to 1st doc
let page = secondDocument.page(at: 5)
// And insert this page as first
firstDocument.insert(page, at: 0)
Enter fullscreen mode Exit fullscreen mode

Don’t forget to save your document after insertion:

firstDocument.write(to: URL_TO_YOUR_FIRST_DOC)
Enter fullscreen mode Exit fullscreen mode

Remove page from PDF Document

Removing pages is easy as well:

let pdfDocument = PDFDocument(url: URL_TO_YOUR_DOC)
pdfDocument.removePage(at: 0) // removing the first page
firstDocument.write(to: URL_TO_YOUR_DOC)
Enter fullscreen mode Exit fullscreen mode

That’s it.

💖 💪 🙅 🚩
artem_poluektov
Artem Poluektov

Posted on March 19, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related