简体   繁体   中英

Update PDF View in Swift with PDFKit using existing PDF file

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")
                    }
                }
            }
    }
}

I did not go through all of your code, but this is what worked for me in the past:

extension PDFPage {
    
    func clearAnnotations() {
        // get only our annotations, not the other annotations on the page
        let ourAnnotations = self.annotations.filter { $0.id == MyAnnotation.id} // <-- here adjust for your purpose
        for anno in ourAnnotations {
            self.removeAnnotation(anno)
        }
    }
 
}

 // use it like this to clear all annotations 
 if let page = pdfView?.document?.page(at: 0) {
     page.clearAnnotations()
 }

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM