I followed this guide https://blog.techchee.com/pdf-composer-app-swiftui/ to be able to draw on PDFs and I was able to load in an existing PDF file and draw on that, but now all my drawings overlap each other.
For example, I could fill out the form once with some User name and Company name, but maybe I made a mistake in the spelling and go back to modify it. When I open the PdfView again, it draws on top of the existing text instead of starting fresh as I expected it to.
Is there a way to delete all drawings from a PdfDocument’s data and start over or anything like that?
I have XCode 12 and Swift 5. Thanks!
Here’s a really simple example:
User class:
class User {
var name: String
var company: String
init(name: String, company: String) {
self.name = name
self.company = company
}
}
Creation of the PDF:
struct PdfCreation {
private var user: User
private var fileName: String
let attributes = [
NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 20)
]
let pageRect = CGRect(x: 0, y: 0, width: (8.5 * 72.0), height: (11 * 72.0))
init(user: User) {
self.user = user
// can replace filename with any resource saved in project
// I have a pdf named Check.pdf that I use
self.fileName = "Check"
}
private func resourceUrl() -> URL? {
if let resourceUrl = Bundle.main.url(forResource: self.fileName,
withExtension: "pdf") {
return resourceUrl
}
return nil
}
func getPdfData() -> Data? {
if let url = resourceUrl() {
if let doc = PDFDocument(url: url) {
let page: PDFPage = doc.page(at: 0)!
var mediaBox: CGRect = page.bounds(for: .mediaBox)
let context = CGContext(url as CFURL, mediaBox: &mediaBox, nil)
UIGraphicsPushContext(context!)
context!.beginPDFPage(nil)
// Draws the PDF into the context
page.draw(with: .mediaBox, to: context!)
let flipVertical: CGAffineTransform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: mediaBox.size.height)
context!.concatenate(flipVertical)
// draw anything you want here
addName()
addCompany()
context!.endPDFPage()
context?.closePDF()
UIGraphicsPopContext()
let pdfData = doc.dataRepresentation()
return pdfData
}
return nil
}
return nil
}
}
extension PdfCreation {
private func addName() {
let width = 200
let x = Int(self.pageRect.width) - width
let y = 80
let height = 40
let nameRect = CGRect(x: x, y: y, width: width, height: height)
user.name.draw(in: nameRect, withAttributes: attributes)
}
private func addCompany() {
let x = 180
let y = 125
let width = Int(self.pageRect.width) - x - 100
let height = 40
let companyRect = CGRect(x: x, y: y, width: width, height: height)
user.company.draw(in: companyRect, withAttributes: attributes)
}
}
PDFView
struct PdfViewer: UIViewRepresentable {
private var data: Data? // pdf data
init(data: Data?) {
self.data = data
}
func makeUIView(context: Context) -> PDFView {
let pageRect = CGRect(x: 0, y: 0, width: (8.5 * 72.0), height: (11 * 72.0))
let pdfView = PDFView(frame: pageRect)
pdfView.autoScales = true
// create PDFDocument from the data given
if let data = self.data {
pdfView.document = PDFDocument(data: data)
}
return pdfView
}
func updateUIView(_ uiView: PDFView, context: Context) {
// Empty
}
}
The actual view being navigated to
struct PdfPreviewViewer: View {
private var user: User
private var data: Data?
init(user: User) {
self.user = user
self.data = PdfCreation(user: user).getPdfData()
}
func actionSheet() {
// share pdf
let activityVC = UIActivityViewController(activityItems: [self.data as Any], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(activityVC, animated: true, completion: nil)
}
var body: some View {
PdfViewer(data: data)
.navigationTitle(Text("Your PDF"))
.toolbar() {
ToolbarItemGroup(placement: .bottomBar) {
Spacer()
// Share Button
Button(action: actionSheet) {
Image(systemName: "square.and.arrow.up")
}
}
}
}
}
2
Answers
I took some inspiration from workingdog's answer and decided to move from drawings to PDFAnnotations and it came out even better than I thought it would. I used this guide to draw annotations:
https://pspdfkit.com/blog/2021/adding-annotations-in-swift-with-pdfkit-vs-pspdfkit/
and by loading in my PDF first and then adding the annotations to the PDFView I was able to extract the data and share it, and change the annotations upon navigating to the viewing page.
I did not go through all of your code, but this is what worked for me in the past: