How do I draw something on a PDF in Swift?

3k views Asked by At

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

2

There are 2 answers

0
Tom J On BEST ANSWER

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.)

0
matt On

A simple solution is demonstrated in the 2017 WWDC video on PDFKit. I assume you have an existing document to which you want to add some drawing. Here's what to do:

  1. Give the document a delegate.

  2. In the delegate, implement classForPage to declare a class for your pages: that class should be your own PDFPage subclass.

  3. In your PDFPage subclass, implement draw(with:to:). You are given a context; draw into it! Be sure to call super if you want the default drawing to happen.

If your PDFPage subclass needs to draw different things on different pages, it can find out where it is in the document by asking for self.document?.index(for:self).