When translating from SwiftUI space to PDF Space, I am struggling to get my output to work. I have a simple PrintView element that is .framed as .frame(width:143, height: 134)
When I run the following code, I end up with all the PrintView's overlaying each other at the top left of the PDF page. I've tried manipulating my x/y cooridnates with both move(to:
and .translateBy
but neither seem to do anything different.
@MainActor func render(viewsPerPage: Int) -> URL {
let eventsArray: [Event] = events.map { $0 }
let url = URL.documentsDirectory.appending(path: "\(recipient.wrappedFirstName)-\(recipient.wrappedLastName)-cards.pdf")
var pageSize = CGRect(x: 0, y: 0, width: 612, height: 792)
guard let pdfOutput = CGContext(url as CFURL, mediaBox: &pageSize, nil) else {
return url
}
let numberOfPages = Int((events.count + viewsPerPage - 1) / viewsPerPage) // Round to number of pages
let xColumn = [0.0, 153.0, 306.0, 459.0]
let yRow = [548.0, 413.0, 269.0, 115.0, 0.0]
let viewsPerRow = 4
let rowsPerPage = 5
let spacing = 10.0
// Note the page should be laid out as follows
// Header Start on Row 792 to Row 692 (100 Pixels)
// Body is a Grid of 143w X 134h PrintViews
// Footer Starts on Row 0 to Row 20 (20 Pixels)
for pageIndex in 0..<numberOfPages {
pdfOutput.beginPDFPage(nil)
// let rendererTop = ImageRenderer(content: AddressView(recipient: recipient))
let rendererTop = ImageRenderer(content: Color.red.frame(width: pageSize.width, height: 90))
rendererTop.render { size, renderTop in
// Go to Bottom Left of Page
pdfOutput.move(to: CGPoint(x: 0.0, y: 0.0))
// Translate to top Left with size of AddressView and Padding
pdfOutput.translateBy(x: 0.0, y: pageSize.height - size.height - spacing)
renderTop(pdfOutput)
print("\n\nStarting page = \(pageIndex)")
}
let startIndex = pageIndex * viewsPerPage
let endIndex = min(startIndex + viewsPerPage, eventsArray.count)
for row in 0..<rowsPerPage {
let yTranslation = yRow[row]
for col in 0..<viewsPerRow {
let index = startIndex + row * viewsPerRow + col
if index < endIndex, let event = eventsArray[safe: index] {
let xTranslation = xColumn[col] // CGFloat(col) * (viewWidth + spacing)
// let renderBody = ImageRenderer(content: PrintView(event: event))
let renderBody = ImageRenderer(content: Text("Event[\(index)] x=\(xColumn[col])/y=\(yRow[row] - 148)").frame(width: 134, height: 148).background(Color.blue))
renderBody.render { size, renderBody in
pdfOutput.move(to: CGPoint(x: xColumn[col], y: yRow[row] - size.height))
renderBody(pdfOutput)
print("Event \(index) Position x= \(xColumn[col]) / y = \(yRow[row] - 148)")
}
}
}
}
let renderBottom = ImageRenderer(content: Text("Page \((pageIndex + 1).formatted()) of \(numberOfPages.formatted())").frame(width: pageSize.width, height: 20).background(Color.yellow))
pdfOutput.move(to: CGPoint(x: pageSize.width / 2 , y: 0))
renderBottom.render { size, renderBottom in
renderBottom(pdfOutput)
print("\nEnding page = \(pageIndex)")
}
pdfOutput.endPDFPage()
}
pdfOutput.closePDF()
return url
}
To make this more expressive, I am now rendering big boxes for each item... When I have only 1 event, The Event overlaps the renderHeader on the top left, but shows x= 0.0 and y=400.
It appears that the pdfOutput.move(to: CGPoint(x: xColumn[col], y: yRow[row] - size.height))
does actually move the position in the rendering space at all.