Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a PDF in iOS programmatically?

I want to create a PDF file in iOS ,there should be one table in the PDF, which is filled from one array. I already searched on Google, but didn't succeed. Any help is appreciated

like image 445
Vikas S Singh Avatar asked Oct 21 '11 09:10

Vikas S Singh


1 Answers

Something like this routine to render the text:

- (CFRange)renderTextRange:(CFRange)currentRange andFrameSetter:(CTFramesetterRef)frameSetter intoRect:(CGRect)frameRect {
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
CTFrameRef frameRef = CTFramesetterCreateFrame(frameSetter, currentRange, framePath, NULL);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext);
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);  
CGContextTranslateCTM(currentContext, 0, 792); 
CGContextScaleCTM(currentContext, 1.0, -1.0);
CTFrameDraw(frameRef, currentContext);
CGContextRestoreGState(currentContext);
CGPathRelease(framePath);
currentRange = CTFrameGetVisibleStringRange(frameRef);
currentRange.location += currentRange.length;
currentRange.length = 0;
CFRelease(frameRef);
return currentRange;
}

And the following code snippet which calls it, assuming you have the context and any fonts etc created and in the appropriate variables. The following loop simply builds up the text line by line into an NSMutableAttributedString which you can then render:

CTFontRef splainFont = CTFontCreateWithName(CFSTR("Helvetica"), 10.0f, NULL);
CGFloat margin = 32.0f;
CGFloat sink = 8.0f;

NSMutableAttributedString *mainAttributedString = [[NSMutableAttributedString alloc] init];
NSMutableString *mainString = [[NSMutableString alloc] init];

// Ingredients is an NSArray of NSDictionaries
// But yours could be anything, or just an array of text.
for (Ingredient *ingredient in ingredients) {
    NSString *ingredientText = [NSString stringWithFormat:@"%@\t%@
        \n",ingredient.amount,ingredient.name];
    [mainString appendString:ingredientText];
    NSMutableAttributedString *ingredientAttributedText =
        [[NSMutableAttributedString alloc] initWithString:ingredientText];
    [ingredientAttributedText addAttribute:(NSString *)(kCTFontAttributeName)
        value:(id)splainFont
        range:NSMakeRange(0, [ingredientText length])];
    [mainAttributedString appendAttributedString:ingredientAttributedText];
    [ingredientAttributedText release];
}

Now you have your array written out with newlines to one NSMutableAttributedString you can render it, depending on your text you might want to render it out in a loop until the rendered location matches your text length. Something like:

// Render Main text.
CTFramesetterRef mainSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)mainAttributedString);
currentRange = [KookaDIS renderTextRange:currentRange 
    andFrameSetter:mainSetter 
    intoRect:pageRect];

// If not finished create new page and loop until we are.
while (!done) {
    UIGraphicsBeginPDFPageWithInfo(pageRect, nil);

    currentRange = [self renderTextRange:currentRange 
        andFrameSetter:mainSetter 
        intoRect:pageRect];

    if (currentRange.location >= [mainString length]) {
        done = TRUE;
    }
}

The above code will need quite a bit of adapting I'm sure as it's hacked out of a project of my own so some variables (like the frame setter) won't exist and you need to close off the PDF context and release variables etc. Note how mainString is used to determine when the text has been rendered out.

It should give a clear enough indication of how to loop around an array or any other group to render an arbitrary length of text into a document.

Slight modifications to the while loop and the one render before entering it will let you render text out in multiple columns too.

like image 191
Diziet Avatar answered Oct 22 '22 19:10

Diziet