NEW: Join my free 100 Days of SwiftUI challenge today! >>

How to watermark PDFs inside a PDFView

Swift version: 5.1

Paul Hudson    @twostraws   

PDFKit makes it easy to watermark PDFs as they are rendered, for example to add “FREE SAMPLE” over pages. It takes six steps, five of which are trivial and one which involves a little Core Graphics heavy lifting.

Let’s get the easy stuff out of the way:

  1. Create a new Cocoa Touch Class called “SampleWatermark”, making it a subclass of PDFPage.
  2. Add import PDFKit to the top of the new file.
  3. Open whichever view controller owns your PDFView and make the ViewController class conform to the PDFDocumentDelegate protocol.
  4. Find the code where you load your document (something like pdfView.document = document) then insert this directly before: document.delegate = self. That means the document will ask your view controller what class it should use to render pages.
  5. Finally, we need to add a new method to the view controller to tell it to use the SampleWatermark class for its pages.

Add this method to your view controller now:

func classForPage() -> AnyClass {
    return SampleWatermark.self
}

What we’ve just done is create a new PDFPage subclass that will handle watermark rendering, then tell our PDFDocument to use it for all pages. We haven’t given the SampleWatermark class any code yet, which means it will look just like a regular page – we’re going to fix that now.

When doing custom PDF rendering there are a few things to know:

  1. If you draw your content before calling super.draw(), your content will appear behind the page content. That might be what you want, but we’ll be doing the opposite here.
  2. You’re given a graphics context to draw into, but you should tread carefully: save the context and its state before you make any changes, then restore them afterwards.
  3. PDFs have a variety of drawing boxes that determine how things are displayed. We don’t care which one is used, but we do need to ask PDFKit to tell us the page bounds for that box so we know how to position our text.
  4. UIKit and PDFs draw in different directions, but you can correct that by moving the drawing position down by the height of the document then flipping its Y axis.

We’re going to write the words “FREE SAMPLE” in red, centered near the top of each page using a bold font. Add this method to SampleWatermark.swift:

override func draw(with box: PDFDisplayBox, to context: CGContext) {
    super.draw(with: box, to: context)

    let string: NSString = "FREE SAMPLE"
    let attributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.red, .font: UIFont.boldSystemFont(ofSize: 32)]
    let stringSize = string.size(withAttributes: attributes)

    UIGraphicsPushContext(context)
    context.saveGState()

    let pageBounds = bounds(for: box)
    context.translateBy(x: (pageBounds.size.width - stringSize.width) / 2, y: pageBounds.size.height)
    context.scaleBy(x: 1.0, y: -1.0)

    string.draw(at: CGPoint(x: 0, y: 55), withAttributes: attributes)

    context.restoreGState()
    UIGraphicsPopContext()
}

If everything went well you should now see “FREE SAMPLE” emblazoned across every page of your PDF.

LEARN SWIFTUI FOR FREE I have a massive, free SwiftUI video collection on YouTube teaching you how to build complete apps with SwiftUI – check it out!

Available from iOS – learn more in my book Advanced iOS: Volume Two

Similar solutions…

About the Swift Knowledge Base

This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 5.0/5