BLACK FRIDAY: Save 50% on my Swift books and videos! >>

How to watermark PDFs inside a PDFView

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.

Available from iOS – learn more in my book Practical iOS 11

Did this solution work for you? Please pass it on!

Other people are reading…

About the Swift Knowledge Base

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

Swift on the server is here

Get ahead of the game and learn server-side Swift with my latest book – build real-world projects while you learn!

MASTER SWIFT NOW
Buy Testing Swift Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let me know!

Click here to visit the Hacking with Swift store >>