Reputation: 138
import UIKit
import PDFKit
class ViewController: UIViewController {
@IBOutlet weak var pdfView: PDFView!
lazy var pdfDoc:PDFDocument? = {
guard let path = Bundle.main.path(forResource: "6368", ofType: "pdf") else {return nil}
let url = URL(fileURLWithPath: path)
return PDFDocument(url: url)
}()
override func viewDidLoad() {
super.viewDidLoad()
self.setupPDFView()
self.save()
}
func setupPDFView() {
//Setup and put pdf on view
pdfView.autoScales = true
pdfView.displayMode = .singlePageContinuous
pdfView.displayDirection = .horizontal
pdfView.document = pdfDoc
self.add(annotation: self.circleAnnotation(), to: 0)
}
func add(annotation: PDFAnnotation, to page:Int){
self.pdfDoc?.page(at: page)?.addAnnotation(annotation)
}
func circleAnnotation()->PDFAnnotation {
let bounds = CGRect(x: 20.0, y: 20.0, width:200.0, height: 200.0)
let annotation = PDFAnnotation(bounds: bounds, forType: .circle, withProperties: nil)
annotation.interiorColor = UIColor.black
return annotation
}
func save() {
//Save to file
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {return}
let data = pdfView.document?.dataRepresentation()
do {
if data != nil{try data!.write(to: url)}
}
catch {
print(error.localizedDescription)
}
}
}
This is just simple PDFKit
code that should add a circle to a pdf's page one and save it to the documents directory. All works, except the save. When I breakpoint just after let data = ..
. it shows that there is data, however, there are two errors:
1) 2018-12-18 05:10:28.887195-0500 PDFWriteTest[21577:1331197] [Unknown process name] Failed to load /System/Library/PrivateFrameworks/CorePDF.framework/Versions/A/CorePDF
2) The file “Documents” couldn’t be saved in the folder “D3E23B05-92...”.
Can this issue (saving PDF data to file) be resolved using PDFKit?
Upvotes: 2
Views: 2956
Reputation: 285069
You cannot write data directly to the URL representing the Documents
folder, you have to specify (and append) a file name.
func save(filename : String) {
//Save to file
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first,
let data = pdfView.document?.dataRepresentation() else {return}
let fileURL = url.appendingPathComponent(filename)
do {
try data.write(to: fileURL)
} catch {
print(error.localizedDescription)
}
}
Upvotes: 6
Reputation: 4008
You can call like this:
let data = NSMutableData()
UIGraphicsBeginPDFContextToData(data, .zero, nil)
// process view
UIGraphicsEndPDFContext()
data as Data
// now you get the data
As apple says, use this method UIGraphicsBeginPDFContextToData(_:_:_:)
to save PDF.
Creates a PDF-based graphics context that targets the specified mutable data object.
Declaration
func UIGraphicsBeginPDFContextToData(_ data: NSMutableData, _ bounds: CGRect, _ documentInfo: [AnyHashable : Any]?)
Parameters
data
The data object to receive the PDF output data.
You can also write the pdf view to disk, using UIGraphicsBeginPDFContextToFile(_:_:_:)
UIGraphicsBeginPDFContextToFile(filePath, .zero, nil)
// do the view rendering
UIGraphicsEndPDFContext()
Here is a example:
class ViewController: UIViewController {
// handles the views, and call to save it as PDF view
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let v1 = UIScrollView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
v1.contentSize = CGSize(width: 100, height: 100)
let v2 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 200))
let v3 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 200))
v1.backgroundColor = UIColor.red
v2.backgroundColor = UIColor.green
v3.backgroundColor = UIColor.blue
let dst = NSHomeDirectory() + "/dng.pdf"
UIGraphicsBeginPDFContextToFile(dst, .zero, nil)
[v1, v2, v3].forEach{ (view : UIView)
in
autoreleasepool {
self.renderPDFPage(view: view)
}
}
UIGraphicsEndPDFContext()
}
// starts to render
func renderPDFPage(view: UIView) {
func renderScrollView(_ scrollView: UIScrollView) {
let tmp = scrollView.tempInfo
scrollView.transformForRender()
_render(scrollView) { scrollView in
if let scrollView = scrollView as? UIScrollView{
scrollView.restore(tmp)
}
}
}
if let scrollView = view as? UIScrollView {
renderScrollView(scrollView)
} else {
_render(view)
}
}
func getPageSize(_ view: UIView) -> CGSize {
switch view {
case (let scrollView as UIScrollView):
return scrollView.contentSize
default:
return view.frame.size
}
}
func _render(_ view: UIView, completion: (UIView) -> Void = { _ in }) {
let size: CGSize = getPageSize(view)
guard size.width > 0 && size.height > 0 else {
return
}
guard let context = UIGraphicsGetCurrentContext() else {
return
}
let renderFrame = CGRect(origin: CGPoint(x: 0.0 , y: 0.0),
size: CGSize(width: size.width, height: size.height))
autoreleasepool {
let superView = view.superview
view.removeFromSuperview()
UIGraphicsBeginPDFPageWithInfo(CGRect(origin: .zero, size: renderFrame.size), nil)
context.translateBy(x: -renderFrame.origin.x, y: -renderFrame.origin.y)
view.layer.render(in: context)
superView?.addSubview(view)
superView?.layoutIfNeeded()
completion(view)
}
}
}
// Util methods, to handle UIScrollView
private extension UIScrollView {
typealias TempInfo = (frame: CGRect, offset: CGPoint, inset: UIEdgeInsets)
var tempInfo: TempInfo {
return (frame, contentOffset, contentInset)
}
func transformForRender() {
contentOffset = .zero
contentInset = UIEdgeInsets.zero
frame = CGRect(origin: .zero, size: contentSize)
}
func restore(_ info: TempInfo) {
frame = info.frame
contentOffset = info.offset
contentInset = info.inset
}
}
Upvotes: 2