views:

163

answers:

1

Hi,

Does anybody know of an open source PDF creation project for the iPhone to generate documents from a template (using Quartz)? Or are there any functions people have written for alignment etc? I've seen libHaru but I understand it is lacking some crucial functionality.

Thanks

A: 

You can create a Quartz context with a PDF file as a rendering destination and simply draw into that. For example, the following code will create a PDF file within an NSData object, which you could then attach to an email or save to disk:

NSMutableData *pdfData = [[NSMutableData alloc] init];
CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)pdfData);
const CGRect mediaBox = CGRectMake(0.0f, 0.0f, drawingWidth, drawingHeight);
CGContextRef pdfContext = CGPDFContextCreate(dataConsumer, &mediaBox, NULL);

UIGraphicsPushContext(pdfContext);
CGContextBeginPage(pdfContext, &mediaBox);

// Draw your content here

CGContextEndPage(pdfContext);   
CGPDFContextClose(pdfContext);
UIGraphicsPopContext();

CGContextRelease(pdfContext);
CGDataConsumerRelease(dataConsumer);

There are a few things going on here. First, we create an NSMutableData instance and set it to be a data consumer (a destination for the PDF context to write to). Because Core Graphics uses Core Foundation types, and not Cocoa classes, CGDataConsumerCreateWithCFData() requires a CFMutableDataRef argument. We are able to simply cast the NSMutableData class we created as this type, because NSData is a toll-free bridged class. What that means is that it can be used in either Cocoa methods or Core Foundation functions without conversion between types.

After that, we set the page size of the PDF context (in points) and create a PDF context, using the data consumer we set up before. We then make this the active context for drawing by using UIGraphicsPushContext().

In this case, we are only creating a single page in the PDF we're drawing, so we begin the page, draw, then end the page. If you wanted to do multiple pages, you could repeat this for each page.

Note that all of this drawing will be done in the Quartz coordinate space, so if you've set up your drawing routines to display correctly in an iPhone view, it will be flipped here. To counteract this flipping, you can place the following within your drawing code (after UIGraphicsPushContext()):

CGContextTranslateCTM(context, 0.0f, self.frame.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);
Brad Larson
Thanks for the code. I was also hoping to find higher level wrappers for some of the functionality.
RaelG
@Rael - They've slightly improved some of the overall PDF creation functionality in 3.2+ with UIGraphicsBeginPDFContextToData() and the like, but it sounds like you want something to abstract away the actual typesetting and layout of a page, not the generation of the PDF itself.
Brad Larson
Yes, that's what I meant sorry if I wasn't clear.
RaelG