Search code examples
swiftmacoscocoacgpdf

How do I draw something on a PDF in Swift?


Here is what I am doing currently.

First, I get the document. Next I create a PDF View and assign the document to the view. Then I create a view and do my drawing in the view, then add the view to the PDFView as a subview. Then I convert the PDFView to data, then to PDF document. Since I'm doing the drawing on the first page of the PDF, I remove the first page from the original PDF, insert the new first page, and return the document.

guard let document = PDFDocument(url: url) else { return nil }
guard let page = document.page(at: 0) else { return nil }
let pageBounds = page.bounds(for: .mediaBox)

let pdfView = PDFView(frame: pageBounds)
pdfView.document = document
pdfView.enclosingScrollView?.autohidesScrollers = true

let view = /// code for subview that I am drawing on
pdfView.addSubview(view)

let data = pdfView.dataWithPDF(inside: pageBounds)
guard let pdf = PDFDocument(data: data) else { return nil }

document.removePage(at: 0)
document.insert(pdf.page(at: 0)!, at: 0)
return document

Is there a better way to do this? To add a wrinkle, my final product has a weird scroll bar image (see Screenshot). I tried adding auto hide scrollers & enclosingScrollView?.hasVerticalScroller = false but neither seem to hide the scroll bar.

Thanks in advance!

Scroll Bar Img


Solution

  • So I've solved my own problem. For anyone else stuck like me, here is what I did. For example to draw a box on a page:

    1. create a CGContext (ctx) for PDFDocuments. You can do this either with data or with a URL you want to write to.
    2. create a CGPDFDocument with the document you want to edit
    3. get the CGPage of the CGPDF you want to edit (cgPage)

    and:

    ctx?.beginPDFPage(nil)
    ctx?.drawPDFPage(cgPage)
    ctx?.beginPath()
    let path = CGPath(roundedRect: box as CGRect, cornerWidth: 5, cornerHeight: 5, transform: nil)
    ctx?.setStrokeColor(CGColor.black)
    ctx?.setFillColor(color.cgColor)
    ctx?.setLineWidth(10.0)
    ctx?.addPath(path)
    ctx?.strokePath()
    ctx?.addPath(path)
    ctx?.fillPath()
    ctx?.endPDFPage()
    ctx?.closePDF()
    

    (If you created the context with a URL, close will write to disk. Otherwise you'll have to do something with the PDF data.)