Get graphics context after saving in PDF - Objective C - objective-c

How to get the core graphics context from PDF after saving? For example I am creating a rectangle inside PDF pages, I need to edit, update or delete that rectangle inside PDF pages after saving it.
Here is the code I used to save rectangle inside PDF pages in objective c.
CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)[[NSBundle mainBundle] URLForResource:#"tutorial" withExtension:#"pdf"]);
const size_t numberOfPages = CGPDFDocumentGetNumberOfPages(pdf);
NSMutableData* data = [NSMutableData data];
UIGraphicsBeginPDFContextToData(data, CGRectZero, nil);
for(size_t page = 1; page <= numberOfPages; page++)
{
// Get the current page and page frame
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdf, page);
const CGRect pageFrame = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);
// Draw the page (flipped)
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -pageFrame.size.height);
CGContextDrawPDFPage(ctx, pdfPage);
CGContextRestoreGState(ctx);
// Draw a red box
[[UIColor redColor] set];
UIRectFill(CGRectMake(20, 20, 100, 100));
}
UIGraphicsEndPDFContext();
CGPDFDocumentRelease(pdf);
pdf = nil;
Now I need to edit or delete the rectangle created above. Please advice !!!

It is not possible to remove content from the PDF file using the CoreGraphics API.
You need to redesign your code to draw or not the rectangle in the PDF file based on some condition.

Related

iOS 8 API printing PDFs: broken when drawing text?

I have an app that has been happily generating PDFs using quartz/UIKit since iOS 4, but since upgrading the project to iOS 8, crashes whenever it tries to render text into the PDF context. Drawing lines & rectangles is fine, but any permutation of string rendering fails with an exception in one of the low level libraries.
Rather than posting my own source, I tried working backwards from Apple's documentation. Granted it is out of date, but if it's no longer supposed to work, they ought to have fixed it.
https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GeneratingPDF/GeneratingPDF.html
Adapted source code:
- (void)producePDF
{
NSString *text=#"Bzorg blarf gloop foo!";
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, (CFStringRef)text, NULL);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
NSString *pdfFileName = fullPath;
// Create the PDF context using the default page size of 612 x 792.
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
CFRange currentRange = CFRangeMake(0, 0);
NSInteger currentPage = 0;
BOOL done = NO;
do {
// Mark the beginning of a new page.
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
// Draw a page number at the bottom of each page.
currentPage++;
//[self drawPageNumber:currentPage];
// Render the current page and update the current range to
// point to the beginning of the next page.
//currentRange = [self renderPageWithTextRange:currentRange andFramesetter:framesetter];
currentRange=[self renderPage:currentPage withTextRange:currentRange andFramesetter:framesetter];
// If we're at the end of the text, exit the loop.
if (currentRange.location == CFAttributedStringGetLength((CFAttributedStringRef)currentText))
done = YES;
} while (!done);
// Close the PDF context and write the contents out.
UIGraphicsEndPDFContext();
// Release the framewetter.
CFRelease(framesetter);
// Release the attributed string.
CFRelease(currentText);
}
- (CFRange)renderPage:(NSInteger)pageNum withTextRange:(CFRange)currentRange
andFramesetter:(CTFramesetterRef)framesetter
{
// Get the graphics context.
CGContextRef currentContext = UIGraphicsGetCurrentContext();
// Put the text matrix into a known state. This ensures
// that no old scaling factors are left in place.
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
// Create a path object to enclose the text. Use 72 point
// margins all around the text.
CGRect frameRect = CGRectMake(72, 72, 468, 648);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
// Get the frame that will do the rendering.
// The currentRange variable specifies only the starting point. The framesetter
// lays out as much text as will fit into the frame.
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);
// Core Text draws from the bottom-left corner up, so flip
// the current transform prior to drawing.
CGContextTranslateCTM(currentContext, 0, 792);
CGContextScaleCTM(currentContext, 1.0, -1.0);
// Draw the frame.
CTFrameDraw(frameRef, currentContext);
// Update the current range based on what was drawn.
currentRange = CTFrameGetVisibleStringRange(frameRef);
currentRange.location += currentRange.length;
currentRange.length = 0;
CFRelease(frameRef);
return currentRange;
}
I've tried numerous permutations, and they all seem to fail at the exact point of rendering text. The Apple-derived example above dies at the line:
CTFrameDraw(frameRef, currentContext);
Other code attempts to get the minimum working:
NSMutableParagraphStyle* textStyle = NSMutableParagraphStyle.defaultParagraphStyle.mutableCopy;
textStyle.alignment = NSTextAlignmentLeft;
NSDictionary* textFontAttributes = #{
NSFontAttributeName: [UIFont fontWithName: #"Helvetica" size: 12], NSForegroundColorAttributeName: UIColor.redColor,
NSParagraphStyleAttributeName: textStyle};
[#"Hello, World!" drawAtPoint:CGPointZero withAttributes:textFontAttributes];
... crashes at the "drawAtPoint" call.
For what it's worth, if I execute the app on a device without the debugger attached (i.e. run/kill/launch from springboard), the PDF creation works just fine. Presumably whatever bogus exception was getting thrown just gets ignored in real life.

Create a PDF file with multiple pages in Quartz2d

I am currently working on an iOS PDF reader. I am able to draw annotations on pages of a PDF file. However, I cannot export such a PDF file with more than one page.
I wrote a function which can export only the first page:
- (void)createPDFFileFromPath:(NSString*)oldPath to:(NSString*)newPath{
CFStringRef path = CFStringCreateWithCString (NULL, [oldPath cStringUsingEncoding:NSUTF8StringEncoding],kCFStringEncodingUTF8);
CFURLRef url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, 0);
CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(url);
int pageCount = CGPDFDocumentGetNumberOfPages(document);
CGPDFPageRef pdfPage = CGPDFDocumentGetPage(document, 1);
CGRect frame = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
UIGraphicsBeginPDFContextToFile(newPath, frame, nil);
UIGraphicsBeginPDFPageWithInfo(frame, nil);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context,1.0,1.0,1.0,1.0);
CGContextFillRect(context, frame);
//Draw other graphics e.g. annnoation into context here.
// Flip the context so that the PDF page is rendered right side up.
CGContextTranslateCTM(context, 0.0, frame.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawPDFPage(context, pdfPage);
UIGraphicsEndPDFContext();
CGPDFDocumentRelease(document);
}
How can I modify this method in order to export more than one page?

programmatically create links in a PDF file

While I think it is a basic question, I didn't manage to find a response that works yet. I am creating a PDF file by stroking paths to a PDF context, and I want different areas on the drawing to be hyperlinks to outside contents (http://bla.bla). I'd be happy even with areas that are non-intersecting rectangles. Anyone knows how to do that?
check the answer to this question it works:Embed hyperlink in PDF using Core Graphics on iOS.
- (void) drawTextLink:(NSString *) text inFrame:(CGRect) frameRect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform ctm = CGContextGetCTM(context);
// Translate the origin to the bottom left.
// Notice that 842 is the size of the PDF page.
CGAffineTransformTranslate(ctm, 0.0, 842);
// Flip the handedness of the coordinate system back to right handed.
CGAffineTransformScale(ctm, 1.0, -1.0);
// Convert the update rectangle to the new coordiante system.
CGRect xformRect = CGRectApplyAffineTransform(frameRect, ctm);
NSURL *url = [NSURL URLWithString:text];
UIGraphicsSetPDFContextURLForRect( url, xformRect );
CGContextSaveGState(context);
NSDictionary *attributesDict;
NSMutableAttributedString *attString;
NSNumber *underline = [NSNumber numberWithInt:NSUnderlineStyleSingle];
attributesDict = #{NSUnderlineStyleAttributeName : underline, NSForegroundColorAttributeName : [UIColor blueColor]};
attString = [[NSMutableAttributedString alloc] initWithString:url.absoluteString attributes:attributesDict];
[attString drawInRect:frameRect];
CGContextRestoreGState(context);
}

Porting creation of a PDF document from iOS to Mac OS X

I am porting my code from iPhone to Mac and I have no idea how I can do this in Mac. Here's my code that I am trying to convert and I know that there's no UIGraphic in Mac. Can someone point me to a guide or give me a quick hint? Thanks.
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();
Use CGPDFContextCreateWithURL instead of UIGraphicsBeginPDFContextToFile (the parameters are very similar). To begin/end pages, use CGPDFContextBeginPage and CGPDFContextEndPage. When you're done, call CGPDFContextClose instead of UIGraphicsEndPDFContext.
The rest can remain the same – Core Graphics exists on both iOS and Mac OS X – which also means that you could use the functions I've mentioned above on iOS as well if you want to use the same code on both platforms.
Swift 4, macOS High Sierra Update
func generatePdfWithFilePath(thefilePath: String)
{
let url = URL(fileURLWithPath: thefilePath) as CFURL
guard let currentContext = CGContext(url, mediaBox: nil, documentInfo as CFDictionary) else {
return
}
self.context = currentContext
self.context!.beginPDFPage(pageInfo as CFDictionary)
drawReport()
self.context!.endPDFPage()
// Close the PDF context and write the contents out.
self.context!.closePDF()
self.context = nil
//DebugLog("generatePdfWithFilePath() completed")
}

iPad App: Merge PDF files into 1 PDF document / Create PDF Document of multi-page scrollview

I am writing an iPad application which uses a scrollview with page control.
I need to create a PDF of all the pages as 1 PDF file.
So far, I figured that I should loop through all the sub-views (pages) and create PDF files for each (using CGPDFContext). BUT I do need to combine all the files into 1 PDF document. Can you help me to do so??
OR if you have a better way to create a PDF document with multiple pages from this scrollview, that would even be better!!
Please help. I've searched everywhere and saw that Mac OS has something using PDFDocument, insertPage function. I can't find a similar method for iOS??
to create a multi-part PDF:
-(CGContextRef) createPDFContext:(CGRect)inMediaBox path:(NSString *) path
{
CGContextRef myOutContext = NULL;
NSURL * url;
url = [NSURL fileURLWithPath:path];
if (url != NULL) {
myOutContext = CGPDFContextCreateWithURL (url,// 2
&inMediaBox,
NULL);
}
return myOutContext;// 4
}
-(void)createPdfFromScrollview:(UIScrollView *)scrollview
{
CGContextRef pdfContext = [self createPDFContext:CGRectMake(0, 0, WIDTH, HEIGHT) path:outputFilePath];
for(UIView * view in scrollview.subviews)
{
CGContextBeginPage (pdfContext,nil);
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(0, HEIGHT);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(pdfContext, transform);
//Draw view into PDF
[view.layer renderInContext:pdfContext];
CGContextEndPage (pdfContext);
}
CGContextRelease (pdfContext);
}
Hope this helps.