NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

How to render a SwiftUI view to a PDF

Paul Hudson    @twostraws   

Updated for Xcode 14.2

New in iOS 16

SwiftUI’s ImageRenderer class can render views any SwiftUI views to PDFs, and yes: all the text and shapes remain vectors, so they scale up beautifully.

Creating a PDF with ImageRenderer takes eight steps:

  1. Deciding which views you want to render.
  2. Creating a URL where SwiftUI can write the image data.
  3. Calling render() on the image renderer to start your rendering code.
  4. Telling SwiftUI how big you want the PDF to be. This might be a fixed size like A4 or US Letter, or might be the size of the view hierarchy you’re rendering.
  5. Create a CGContext object to handle the PDF pages.
  6. Starting a new page.
  7. Rendering the SwiftUI views onto that page.
  8. Ending the page and closing the PDF document.

Once that finishes the PDF URL is yours to do with as you please.

I know that sounds like a lot of work, but the total amount of code isn’t so bad. Here’s a complete example that renders a view to a PDF to be exported using ShareLink, with comments matching the explanation above:

@MainActor
struct ContentView: View {
    var body: some View {
        ShareLink("Export PDF", item: render())
    }

    func render() -> URL {
        // 1: Render Hello World with some modifiers
        let renderer = ImageRenderer(content:
            Text("Hello, world!")
                .font(.largeTitle)
                .foregroundColor(.white)
                .padding()
                .background(.blue)
                .clipShape(Capsule())
        )

        // 2: Save it to our documents directory
        let url = URL.documentsDirectory.appending(path: "output.pdf")

        // 3: Start the rendering process
        renderer.render { size, context in
            // 4: Tell SwiftUI our PDF should be the same size as the views we're rendering
            var box = CGRect(x: 0, y: 0, width: size.width, height: size.height)

            // 5: Create the CGContext for our PDF pages
            guard let pdf = CGContext(url as CFURL, mediaBox: &box, nil) else {
                return
            }

            // 6: Start a new PDF page
            pdf.beginPDFPage(nil)

            // 7: Render the SwiftUI view data onto the page
            context(pdf)

            // 8: End the page and close the file
            pdf.endPDFPage()
            pdf.closePDF()
        }

        return url
    }
}

Download this as an Xcode project

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Similar solutions…

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI 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 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 Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.