I am trying to use ImageRenderer to print a simple table in PDF but I am quite struggling.
I am quite confused about positioning and measures here.
Here is the code:
import SwiftUI
import QuickLook
struct Stat: Identifiable, Equatable {
var id: String
let totalMatches: Int
let points: Int
}
struct GridView: View {
let stats: [Stat]
var body: some View {
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
GridRow(alignment: .center) {
Text("ID")
Text("Matches")
Text("Points")
}.frame(maxWidth: .infinity)
.frame(height: 50)
.bold()
.font(.headline)
.background(.pink)
.frame(maxWidth: .infinity)
ForEach(Array(stats.enumerated()), id: .1.id) { (index, stat) in
GridRow(alignment: .center) {
Text(stat.id)
Text(stat.totalMatches, format: .number)
Text(stat.points, format: .number)
}.frame(maxHeight: .infinity)
.frame(maxWidth: .infinity)
.background(index % 2 == 0 ? Color.white : Color.gray.opacity(0.2))
}
}
.background(.purple.opacity(0.2))
}
}
struct ExportImagesView: View {
@State private var image = Image(systemName: "heart")
private let pages = ["Page1"]
private let stats = [
Stat(id: UUID().uuidString, totalMatches: 4, points: 12),
Stat(id: UUID().uuidString, totalMatches: 9, points: 31),
Stat(id: UUID().uuidString, totalMatches: 4, points: 14),
Stat(id: UUID().uuidString, totalMatches: 1, points: 0),
]
var body: some View {
VStack(spacing: 20) {
image
Divider()
HStack {
ShareLink("Export", item: render())
Spacer()
Button {
render()
} label: {
Text("Render")
}
}.padding()
}
}
@MainActor
@discardableResult
func render() -> URL {
let url = URL.documentsDirectory.appending(path: "output.pdf")
var box = CGRect(x: 0, y: 0, width: 595.2, height: 841.8)
guard let pdf = CGContext(url as CFURL, mediaBox: &box, nil) else {
return url
}
for _ in pages {
pdf.beginPDFPage(nil)
let renderer = ImageRenderer(content: GridView(stats: stats))
renderer.render { size, context in context(pdf)}
pdf.endPDFPage()
}
pdf.closePDF()
if let cgImage = pdf.makeImage() {
let uiImage = UIImage(cgImage: cgImage)
image = Image(uiImage: uiImage)
}
return url
}
}
struct ExportImagesView_Previews: PreviewProvider {
static var previews: some View {
ExportImagesView()
}
}
There are two main issues. First is, I can’t make a preview of a pdf. I tried to use makeImage()
method on CGContext
but it fails.
Also, there is more issues with positioning of a content before printing. Here is how pdf looks:
Since CGContext
uses a different coordinate system than SwiftUI, everything is positioned at the bottom of the screen. I attempted to use .scaleBy(), but unfortunately, that didn’t change anything.
Could somebody please provide guidance on how to properly adjust the positioning in CGContext to align with SwiftUI’s coordinate system and how to make a preview work?