Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS - Generating PDF from UIView by rendering loses quality

I've used the following methods to generate a PDF from a UIView. All of them create the PDF but loses quality:

Method 1:

@implementation UIView(PDFWritingAdditions)

- (void)renderInPDFFile:(NSString*)path
{
    CGRect mediaBox = self.bounds;
    CGContextRef ctx = CGPDFContextCreateWithURL((__bridge_retained CFURLRef)[NSURL fileURLWithPath:path], &mediaBox, NULL);
    CGPDFPageRef page;
    CGContextDrawPDFPage(ctx, page);

    CGPDFContextBeginPage(ctx, NULL);

    // Also tried following commented lines but no luck
    //    CGContextSetFlatness(ctx, 0.1);
    //    CGContextSetAllowsAntialiasing(ctx, YES);
    //    CGContextSetAllowsFontSmoothing(ctx, YES);
    //    CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh);
    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -mediaBox.size.height);
    [self.layer renderInContext:ctx];
    CGPDFContextEndPage(ctx);
    CFRelease(ctx);
}

@end

Method 2:

- (void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
    // Creates a mutable data object for updating with binary data, like a byte array
    NSMutableData *pdfData = [NSMutableData data];

    // Points the pdf converter to the mutable data object and to the UIView to be converted
    UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil);
    UIGraphicsBeginPDFPage();
    CGContextRef pdfContext = UIGraphicsGetCurrentContext();


    // draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData

    [aView.layer renderInContext:pdfContext];

    // remove PDF rendering context
    UIGraphicsEndPDFContext();

    // Retrieves the document directories from the iOS device
    NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);

    NSString* documentDirectory = [documentDirectories objectAtIndex:0];
    NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename];

    // instructs the mutable data object to write its context to a file on disk
    [pdfData writeToFile:documentDirectoryFilename atomically:YES];
    NSLog(@"documentDirectoryFileName: %@",documentDirectoryFilename);
}

I think I may be missing some settings for the pdf context, not sure. Also I've create png image from UIView with following method which is exact same quality:

- (UIImage *)imageFromView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();
    // Retrieves the document directories from the iOS device
    NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);

    NSString* documentDirectory = [documentDirectories objectAtIndex:0];
    NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:@"pdf.png"];

    // instructs the mutable data object to write its context to a file on disk
    [UIImagePNGRepresentation(img) writeToFile:documentDirectoryFilename atomically:YES];
    NSLog(@"documentDirectoryFileName: %@",documentDirectoryFilename);
    return img;
}

Can someone see what I'm doing wrong? Thanks.

like image 917
iEamin Avatar asked Oct 30 '11 04:10

iEamin


1 Answers

Is this using a retina display? It could be a contentsScale thing. Have a look at this SO post

EDIT Ok, now that you've posted before & after pics, I see that what you want the invoice UIView to be rendered as nice, high quality, printable vector data in your PDF.

I'm pretty sure that [CALayer renderInContext] always produces raster data, so you're probably better off constructing the PDF manually. And if you're talking about tax invoices, do you really want the layout to change with the next iOS update?

However, you could look at this answer, which reluctantly suggests using the UIView as a template system for your PDF layout.

like image 128
Rhythmic Fistman Avatar answered Sep 28 '22 07:09

Rhythmic Fistman