Reputation: 780
i'm writing an application in objective-c (using cocoa). i have a PDF template, i need to substitute actual values into placeholders in PDF and then save the result into new PDF.
how can i do it? which library should i use?
Upvotes: 11
Views: 13932
Reputation: 1623
I know that the question is about obj-c, but if you are here because of the edit pdf, below there is a solution in Swift 3:
PS: In my solution I needed to edit the document info of the new PDF, so I used the subject parameter to do this.
func createPDF(on path: String?, from templateURL: URL?, with subject: String?) {
guard let newPDFPath = path,
let pdfURL = templateURL else { return }
let options = [(kCGPDFContextSubject as String): subject ?? ""] as CFDictionary
UIGraphicsBeginPDFContextToFile(newPDFPath, .zero, options as? [AnyHashable : Any])
let templateDocument = CGPDFDocument(pdfURL as CFURL)
let pageCount = templateDocument?.numberOfPages ?? 0
for i in 1...pageCount {
//get bounds of template page
if let templatePage = templateDocument?.page(at: i) {
let templatePageBounds = templatePage.getBoxRect(.cropBox)
//create empty page with corresponding bounds in new document
UIGraphicsBeginPDFPageWithInfo(templatePageBounds, nil)
let context = UIGraphicsGetCurrentContext()
//flip context due to different origins
context?.translateBy(x: 0.0, y: templatePageBounds.height)
context?.scaleBy(x: 1.0, y: -1.0)
//copy content of template page on the corresponding page in new file
context?.drawPDFPage(templatePage)
//flip context back
context?.translateBy(x: 0.0, y: templatePageBounds.height)
context?.scaleBy(x: 1.0, y: -1.0)
}
}
UIGraphicsEndPDFContext()
}
Upvotes: 0
Reputation: 2045
I've found the solution! It connects the power of quartz2d and simplicity of UIGraphics.
NSString *newFilePath = @"path/to/your/newfile.pdf";
NSString *templatePath = @"path/to/your/template.pdf";
//create empty pdf file;
UIGraphicsBeginPDFContextToFile(newFilePath, CGRectMake(0, 0, 792, 612), nil);
CFURLRef url = CFURLCreateWithFileSystemPath (NULL, (CFStringRef)templatePath, kCFURLPOSIXPathStyle, 0);
//open template file
CGPDFDocumentRef templateDocument = CGPDFDocumentCreateWithURL(url);
CFRelease(url);
//get amount of pages in template
size_t count = CGPDFDocumentGetNumberOfPages(templateDocument);
//for each page in template
for (size_t pageNumber = 1; pageNumber <= count; pageNumber++) {
//get bounds of template page
CGPDFPageRef templatePage = CGPDFDocumentGetPage(templateDocument, pageNumber);
CGRect templatePageBounds = CGPDFPageGetBoxRect(templatePage, kCGPDFCropBox);
//create empty page with corresponding bounds in new document
UIGraphicsBeginPDFPageWithInfo(templatePageBounds, nil);
CGContextRef context = UIGraphicsGetCurrentContext();
//flip context due to different origins
CGContextTranslateCTM(context, 0.0, templatePageBounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
//copy content of template page on the corresponding page in new file
CGContextDrawPDFPage(context, templatePage);
//flip context back
CGContextTranslateCTM(context, 0.0, templatePageBounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
/* Here you can do any drawings */
[@"Test" drawAtPoint:CGPointMake(200, 300) withFont:[UIFont systemFontOfSize:20]];
}
CGPDFDocumentRelease(templateDocument);
UIGraphicsEndPDFContext();
Upvotes: 25
Reputation: 13003
Probably PDFKit. For some tasks, the high level PDFKit API cannot do what you want, and you might be forced to use the low level CG PDF parsing libraries. They're quite low level, though. They mean really understanding the PDF file format.
Upvotes: 5