How to Edit PDFs in an iOS Application Using a PDF Library
In this post, you’ll learn how to edit PDFs using PSPDFKit for iOS. More specifically, you’ll learn how to perform the following editing operations on a PDF document in your iOS application:
-
Crop pages
-
Add new pages
-
Attach files
-
Add watermarks
Requirements
To get started, you’ll need:
-
A computer running macOS
Getting Started
To follow along, create a fresh Xcode project and add the PSPDFKit Swift package to your project. For step-by-step instructions, follow our Getting Started on iOS guide.
Rotating PDF Pages Using Processor
The Processor
class provides a wide range of APIs for document editing operations. Many Processor
operations involve producing an output that’s the result of performing editing operations on an input document.
Processor
is a great choice if you want to build an automated document processing operation.
-
Load the document you want to edit:
let fileURL = Bundle.main.url(forResource: "YOUR-DOCUMENT", withExtension: "pdf")! let document = Document(url: fileURL)
-
Configure the page rotation parameters on a
Processor.Configuration
instance:guard let configuration = Processor.Configuration(document: document) else { print("Could not create a processor configuration. The document might be locked or invalid.") return } configuration.rotatePage(0, by: Rotation.rotation90)
-
Construct a URL to write the modified document:
let editedDocumentURl = URL(filePath: NSTemporaryDirectory() + "/document-rotated.pdf")
-
Apply the configuration and write the edited document:
let processor = Processor(configuration: configuration, securityOptions: nil) do { try processor.write(toFileURL: editedDocumentURl) } catch { print(error) }
-
Load the edited document and present the PDF view controller:
let editedDocument = Document(url: editedDocumentURl) let pdfController = PDFViewController(document: editedDocument) present(UINavigationController(rootViewController: pdfController), animated: true)
For a working example, replace the contents of ViewController.swift
with the following:
import UIKit import PSPDFKit import PSPDFKitUI class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let fileURL = Bundle.main.url(forResource: "YOUR-DOCUMENT", withExtension: "pdf")! let document = Document(url: fileURL) guard let configuration = Processor.Configuration(document: document) else { print("Could not create a processor configuration. The document might be locked or invalid.") return } // Rotate the first page 90 degrees clockwise. configuration.rotatePage(0, by: Rotation.rotation90) let editedDocumentURL = URL(filePath: NSTemporaryDirectory() + "/document-rotated.pdf") let processor = Processor(configuration: configuration, securityOptions: nil) do { // Write the modified document. `editedDocumentURL` can be used // to initialize and present the edited document. try processor.write(toFileURL: editedDocumentURL) } catch { print(error) } let editedDocument = Document(url: editedDocumentURL) let pdfController = PDFViewController(document: editedDocument) // Present the PDF view controller within a `UINavigationController` to show built-in toolbar buttons. present(UINavigationController(rootViewController: pdfController), animated: true) } }
Remember to replace
YOUR-DOCUMENT
with the document you want to edit.
Cropping PDF Pages Using the Processor Class
To crop a page of your document using Processor
, configure the page cropping parameters on a Processor.Configuration
instance:
// Crop the page to 200×200 pt. configuration.changeCropBoxForPage(at: 0, to: CGRect(x: 0, y: 0, width: 200, height: 200))
For a working example, replace the contents of ViewController.swift
with the following:
import UIKit import PSPDFKit import PSPDFKitUI class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let fileURL = Bundle.main.url(forResource: "YOUR-DOCUMENT", withExtension: "pdf")! let document = Document(url: fileURL) guard let configuration = Processor.Configuration(document: document) else { print("Could not create a processor configuration. The document might be locked or invalid.") return } // Crop the page to 200×200 pt. configuration.changeCropBoxForPage(at: 0, to: CGRect(x: 0, y: 0, width: 200, height: 200)) let editedDocumentURL = URL(filePath: NSTemporaryDirectory() + "/document-cropped.pdf") let processor = Processor(configuration: configuration, securityOptions: nil) do { // Write the modified document. `editedDocumentURL` can be used // to initialize and present the edited document. try processor.write(toFileURL: editedDocumentURL) } catch { print(error) } let editedDocument = Document(url: editedDocumentURL) // The configuration closure is optional and allows additional customization. let pdfController = PDFViewController(document: editedDocument) // Present the PDF view controller within a `UINavigationController` to show built-in toolbar buttons. present(UINavigationController(rootViewController: pdfController), animated: true) } }
Make sure that the file path used in
editedDocumentURL
is unique in the containing directory so that existing documents aren’t overwritten.
Moving PDF Pages Using the Processor Class
To move pages via the Processor
API, configure the page move parameters on a Processor.Configuration
instance:
// Move the first page to the end of the document. configuration.movePages(IndexSet(integer: 0), toDestinationIndex: document.pageCount)
Removing Pages Using the Processor Class
To remove pages via the Processor
API, configure the page removal parameters on a Processor.Configuration
instance:
// Remove the first page. This API can be used to remove multiple pages at the same time. configuration.removePages(IndexSet(integer: 0))
Adding New Pages Using the Processor Class
For this example, you’ll add a blank page to your document using the Processor
API. You can add a blank page to a document using the .blank
template document.
-
Create a blank page template:
let pageTemplate = PageTemplate(pageType: .emptyPage, identifier: .blank)
-
Create a new page configuration:
let newPageConfiguration = PDFNewPageConfiguration(pageTemplate: pageTemplate, builderBlock: nil)
-
Configure the add new page parameters:
configuration.addNewPage(at: 1, configuration: newPageConfiguration)
You’ll have the following in your ViewController.swift
:
import UIKit import PSPDFKit import PSPDFKitUI class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let fileURL = Bundle.main.url(forResource: "YOUR-DOCUMENT", withExtension: "pdf")! let document = Document(url: fileURL) guard let configuration = Processor.Configuration(document: document) else { print("Could not create a processor configuration. The document might be locked or invalid.") return } // Create a blank page template. let pageTemplate = PageTemplate(pageType: .emptyPage, identifier: .blank) // Create a new page configuration. let newPageConfiguration = PDFNewPageConfiguration(pageTemplate: pageTemplate, builderBlock: nil) // Add the blank page at index 1. configuration.addNewPage(at: 1, configuration: newPageConfiguration) let editedDocumentURl = URL(filePath: NSTemporaryDirectory() + "/document-new-page.pdf") let processor = Processor(configuration: configuration, securityOptions: nil) do { // Write the modified document. `editedDocumentURL` can be used // to initialize and present the edited document. try processor.write(toFileURL: editedDocumentURl) } catch { print(error) } let editedDocument = Document(url: editedDocumentURl) // The configuration closure is optional and allows additional customization. let pdfController = PDFViewController(document: editedDocument) // Present the PDF view controller within a `UINavigationController` to show built-in toolbar buttons. present(UINavigationController(rootViewController: pdfController), animated: true) } }
Editing Text in PDFs
PSPDFKit enables you to edit text directly in PDF documents using the built-in user interface via Content Editor. You can change the text color, the font type, and the font size, and you can move and resize text boxes.
To enable content editing programmatically after loading a document, set the view mode to .contentEditing
:
let controller = PDFViewController(document: document) controller.setViewMode(.contentEditing, animated: true)
For a working example, replace the contents of ViewController.swift
with the following:
import UIKit import PSPDFKit import PSPDFKitUI class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Update to use your document name. let fileURL = Bundle.main.url(forResource: "YOUR-DOCUMENT", withExtension: "pdf")! let document = Document(url: fileURL) let controller = PDFViewController(document: document) controller.setViewMode(.contentEditing, animated: true) present(UINavigationController(rootViewController: controller), animated: true) } }
Attaching Files to PDFs
You can programmatically attach embedded files to a FileAnnotation
object. You can create a file annotation with an embedded file using the URL of any file.
This is what a working example will look like:
import UIKit import PSPDFKit import PSPDFKitUI class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Update to use your document name. let fileURL = Bundle.main.url(forResource: "YOUR-DOCUMENT", withExtension: "pdf")! let document = Document(url: fileURL) // Create a new file annotation and set its properties. let fileAnnotation = FileAnnotation() fileAnnotation.pageIndex = 0 fileAnnotation.iconName = .graph fileAnnotation.color = .blue fileAnnotation.boundingBox = CGRect(x: 500, y: 250, width: 32, height: 32) let embeddedFileURL = Bundle.main.url(forResource: "DOCUMENT-TO-EMBED", withExtension: "pdf")! let embeddedFile = EmbeddedFile(fileURL: embeddedFileURL, fileDescription: "Sample Document") fileAnnotation.embeddedFile = embeddedFile document.add(annotations: [fileAnnotation]) // The configuration closure is optional and allows additional customization. let pdfController = PDFViewController(document: document) // Present the PDF view controller within a `UINavigationController` to show built-in toolbar buttons. present(UINavigationController(rootViewController: pdfController), animated: true) } }
Adding Watermarks to PDFs Using the Processor Class
PSPDFKit enables you to draw a permanent watermark on all pages of a document using the Processor
API. The resulting PDF file will have a permanent watermark on all of its pages, even when opened in other PDF editors:
configuration.drawOnAllCurrentPages { context, pageIndex, pageRect, renderOptions in // Careful. This code is executed on background threads. Only use thread-safe drawing methods. let text = "PSPDF Live Watermark On Page \(pageIndex + 1)" let stringDrawingContext = NSStringDrawingContext() stringDrawingContext.minimumScaleFactor = 0.1 // Add text over the diagonal of the page. context.translateBy(x: 0, y: pageRect.size.height / 2) context.rotate(by: -.pi / 4) let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont.boldSystemFont(ofSize: 30), .foregroundColor: UIColor.red.withAlphaComponent(0.5) ] text.draw(with: pageRect, options: .usesLineFragmentOrigin, attributes: attributes, context: stringDrawingContext) }
For a working example, replace the contents of ViewController.swift
with the following:
import UIKit import PSPDFKit import PSPDFKitUI class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Update to use your document name. let fileURL = Bundle.main.url(forResource: "document-ios", withExtension: "pdf")! let document = Document(url: fileURL) guard let configuration = Processor.Configuration(document: document) else { print("Could not create a processor configuration. The document might be locked or invalid.") return } configuration.drawOnAllCurrentPages { context, pageIndex, pageRect, renderOptions in // Careful. This code is executed on background threads. Only use thread-safe drawing methods. let text = "PSPDF Live Watermark On Page \(pageIndex + 1)" let stringDrawingContext = NSStringDrawingContext() stringDrawingContext.minimumScaleFactor = 0.1 // Add text over the diagonal of the page. context.translateBy(x: 0, y: pageRect.size.height / 2) context.rotate(by: -.pi / 4) let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont.boldSystemFont(ofSize: 30), .foregroundColor: UIColor.red.withAlphaComponent(0.5) ] text.draw(with: pageRect, options: .usesLineFragmentOrigin, attributes: attributes, context: stringDrawingContext) } let editedDocumentURl = URL(filePath: NSTemporaryDirectory() + "/document-watermark.pdf") let processor = Processor(configuration: configuration, securityOptions: nil) do { // Write the modified document. `editedDocumentURL` can be used // to initialize and present the edited document. try processor.write(toFileURL: editedDocumentURl) } catch { print(error) } let editedDocument = Document(url: editedDocumentURl) // The configuration closure is optional and allows additional customization. let pdfController = PDFViewController(document: editedDocument) // Present the PDF view controller within a `UINavigationController` to show built-in toolbar buttons. present(UINavigationController(rootViewController: pdfController), animated: true) } }
Conclusion
In this post, you learned how to edit a PDF document using PSPDFKit’s iOS PDF editor library. If you hit any snags while trying to implement any of the steps, don’t hesitate to reach out to our Support team for help. If you want to learn more about how you can use PSPDFKit’s iOS library in your projects, you can reach out to our team.