Blog Post

How to Edit PDFs in an iOS Application Using a PDF Library

Illustration: 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:

Requirements

To get started, you’ll need:

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.

Information

Processor is a great choice if you want to build an automated document processing operation.

  1. Load the document you want to edit:

    let fileURL = Bundle.main.url(forResource: "YOUR-DOCUMENT", withExtension: "pdf")!
    let document = Document(url: fileURL)
  2. 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)
  3. Construct a URL to write the modified document:

    let editedDocumentURl = URL(filePath: NSTemporaryDirectory() + "/document-rotated.pdf")
  4. Apply the configuration and write the edited document:

    let processor = Processor(configuration: configuration, securityOptions: nil)
    do {
        try processor.write(toFileURL: editedDocumentURl)
    } catch {
        print(error)
    }
  5. 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)

    }
}
Information

Remember to replace YOUR-DOCUMENT with the document you want to edit.

gif showing the working example on a simulator

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)

    }
}
Information

Make sure that the file path used in editedDocumentURL is unique in the containing directory so that existing documents aren’t overwritten.

gif showing the working example on a simulator

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)

gif showing the working example on a simulator

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))

gif showing the working example on a simulator

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.

  1. Create a blank page template:

    let pageTemplate = PageTemplate(pageType: .emptyPage, identifier: .blank)
  2. Create a new page configuration:

    let newPageConfiguration = PDFNewPageConfiguration(pageTemplate: pageTemplate, builderBlock: nil)
  3. 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)

    }
}

gif showing the working example on a simulator

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)

   }
}

Image showing the working example on a simulator

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)

    }
}

gif showing the working example on a simulator

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)

   }

}

gif showing the working example on a simulator

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.

Share Post
Free 60-Day Trial Try PSPDFKit in your app today.
Free Trial

Related Articles

Explore more
DEVELOPMENT  |  iOS • Swift • Tips

Privacy Manifests and Required Reason APIs on iOS

PRODUCTS  |  iOS • Releases

PSPDFKit 13.4 for iOS Introduces Revamped API Documentation and Improves Multiple Annotation Selection

DEVELOPMENT  |  visionOS • iOS

Apple’s Vision of Our Digital Future