Earlier, we confirmed you use ImageRenderer
to seize a SwiftUI view and reserve it as a picture. This new class, launched in iOS 16, can even allow you to convert a view right into a PDF doc.
On this tutorial, we are going to construct on the highest of the earlier demo and add the Save to PDF perform. To comply with this tutorial, please use Xcode 14 beta 3 (or up).
Revisit the Demo App
For those who haven’t learn the previous tutorial, I counsel you to test it out first. It already coated the fundamentals of ImageRenderer
and defined the implementation of the demo app.

I’ve made some modifications to the demo app by including a heading and a caption for the road chart. The demo app now additionally comes with a PDF button for saving the chart view in a PDF doc. You may consult with the code of the ChartView
struct under:
var physique: some View {
VStack
Textual content(“Constructing Line Charts in SwiftUI”)
.font(.system(dimension: 40, weight: .heavy, design: .rounded))
.multilineTextAlignment(.heart)
.padding()
Chart
ForEach(chartData, id: .metropolis) collection in
ForEach(collection.knowledge) merchandise in
LineMark(
x: .worth(“Month”, merchandise.date),
y: .worth(“Temp”, merchandise.temperature)
)
.foregroundStyle(by: .worth(“Metropolis”, collection.metropolis))
.image(by: .worth(“Metropolis”, collection.metropolis))
.chartXAxis
AxisMarks(values: .stride(by: .month)) worth in
AxisGridLine()
AxisValueLabel(format: .dateTime.month(.defaultDigits))
.chartPlotStyle plotArea in
plotArea
.background(.blue.opacity(0.1))
.chartYAxis
AxisMarks(place: .main)
.body(width: 350, peak: 300)
.padding(.horizontal)
Textual content(“Determine 1. Line Chart”)
.padding()
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
struct ChartView: View { let chartData = [ (city: “Hong Kong”, data: hkWeatherData), (city: “London”, data: londonWeatherData), (city: “Taipei”, data: taipeiWeatherData) ]
var physique: some View { VStack Textual content(“Constructing Line Charts in SwiftUI”) .font(.system(dimension: 40, weight: .heavy, design: .rounded)) .multilineTextAlignment(.heart) .padding()
Chart ForEach(chartData, id: .metropolis) collection in ForEach(collection.knowledge) merchandise in LineMark( x: .worth(“Month”, merchandise.date), y: .worth(“Temp”, merchandise.temperature) )
.foregroundStyle(by: .worth(“Metropolis”, collection.metropolis)) .image(by: .worth(“Metropolis”, collection.metropolis))
.chartXAxis AxisMarks(values: .stride(by: .month)) worth in AxisGridLine() AxisValueLabel(format: .dateTime.month(.defaultDigits))
.chartPlotStyle plotArea in plotArea .background(.blue.opacity(0.1))
.chartYAxis AxisMarks(place: .main)
.body(width: 350, peak: 300)
.padding(.horizontal)
Textual content(“Determine 1. Line Chart”) .padding()
} } |
Saving the Chart View as a PDF Doc Utilizing ImageRenderer
What we’re going to do is to create a PDF doc for the ChartView
utilizing ImageRenderer
. Whereas it solely takes a pair traces of code to transform a SwiftUI view into a picture, we’d like a bit of extra work for PDF rendering.
For picture conversion, you’ll be able to entry the uiImage
property to get the rendered picture. To attract the chart right into a PDF, we are going to use the render
methodology of ImageRenderer
. Here’s what we’re going to implement:
- Search for the doc listing and put together the rendered path for the PDF file (e.g. linechart.pdf).
- Put together an occasion of
CGContext
for drawing. - Name the
render
methodology of the renderer to render the PDF doc.
For the implementation, we create a brand new methodology named exportPDF
. Beneath is the code of the tactic :
let renderedUrl = documentDirectory.appending(path: “linechart.pdf”)
if let shopper = CGDataConsumer(url: renderedUrl as CFURL),
let pdfContext = CGContext(shopper: shopper, mediaBox: nil, nil)
let renderer = ImageRenderer(content material: chartView)
renderer.render dimension, renderer in
let choices: [CFString: Any] = [
kCGPDFContextMediaBox: CGRect(origin: .zero, size: size)
]
pdfContext.beginPDFPage(choices as CFDictionary)
renderer(pdfContext)
pdfContext.endPDFPage()
pdfContext.closePDF()
print(“Saving PDF to (renderedUrl.path())”)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@MainActor non-public func exportPDF() guard let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else return
let renderedUrl = documentDirectory.appending(path: “linechart.pdf”)
if let shopper = CGDataConsumer(url: renderedUrl as CFURL), let pdfContext = CGContext(shopper: shopper, mediaBox: nil, nil)
let renderer = ImageRenderer(content material: chartView) renderer.render dimension, renderer in let choices: [CFString: Any] = [ kCGPDFContextMediaBox: CGRect(origin: .zero, size: size) ]
pdfContext.beginPDFPage(choices as CFDictionary)
renderer(pdfContext) pdfContext.endPDFPage() pdfContext.closePDF()
print(“Saving PDF to (renderedUrl.path())”)
|
The primary two traces of the code retrieves the doc listing of the consumer and arrange the file path of the PDF file (i.e. line chart.pdf
). We then create the occasion of CGContext
. The mediaBox
parameter is about to nil. On this case, Core Graphics makes use of a default web page dimension of 8.5 by 11 inches (612 by 792 factors).
The renderer
closure receives two parameters: the present dimension of the view, and a perform that renders the view to the CGContext
. To start the PDF web page, we name the context’s beginPDFPage
methodology. The renderer
methodology attracts the chart view. And do not forget that you must shut the PDF doc to finish the entire operation.
To name this exportPDF
methodology, we create a PDF
button like this:
.buttonStyle(.borderedProminent)
Button exportPDF() label: Label(“PDF”, systemImage: “doc.plaintext”)
.buttonStyle(.borderedProminent) |
You may run the app in a simulator to have a check. After you faucet the PDF button, you must see the next message within the console:
Saving PDF to /Customers/simon/Library/Developer/CoreSimulator/Units/CA9B849B–36C5–4608–9D72–B04C468DA87E/knowledge/Containers/Information/Software/04415B8A–7485–48F0–8DA2–59B97C2B529D/Paperwork/linechart.pdf |
For those who open the file in Finder, you must see a PDF doc like under.

To regulate the place of the drawing, you’ll be able to insert this line of code earlier than calling renderer
:
pdfContext.translateBy(x: 0, y: 200) |
It will transfer the chart to the higher a part of the doc.

Make the PDF file accessible to the Recordsdata app
Chances are you’ll marvel why the PDF file can’t be discovered within the Recordsdata app. Earlier than you may make the file accessible to the built-in Recordsdata app, you need to change a few the settings in Data.plist
. Swap to Data.plist
and add the next keys:
UIFileSharingEnabled
– Software helps iTunes file sharingLSSupportsOpeningDocumentsInPlace
– Helps opening paperwork in place
Set the worth of the keys to Sure. When you allow each choices, run the app on the simulator once more. Open the Recordsdata app and navigate to the On My iPhone location. It is best to see the app’s folder. Contained in the folder, you can see the PDF doc.

If you’re enthusiastic about diving deeper into SwiftUI, try our Mastering SwiftUI ebook.