iPDFdev Tips & Tricks for PDF development

Convert a PDF page to image on the iPhone and iPad

March 28th, 2011

A common requirement when working with PDF files is to convert them to images. Because the iOS includes native PDF support, converting a PDF page to image seems easy. A graphic context is created for the image, the PDF page is rendered on image's graphic context and then the image is saved. Yet there is a catch when rendering the PDF page on the image's graphic context.

Now lets see how we put this idea into practice and convert a PDF page to image at a specific resolution.

The page visible area is determined by the page CropBox. The page orientation is given by the page rotation angle. We need these values to compute the size of the destination image.

1
2
    CGRect cropBox = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
    int pageRotation = CGPDFPageGetRotationAngle(page);

Assuming the application will run on iOS 4.x, we can use the UIGraphicsBeginImageContextWithOptions method to create the graphic context and its underlying image.

1
2
3
4
5
6
7
8
9
    if ((pageRotation == 0) || (pageRotation == 180) ||(pageRotation == -180)) {
        UIGraphicsBeginImageContextWithOptions(cropBox.size, NO, resolution / 72); 
    }
    else {
        UIGraphicsBeginImageContextWithOptions(
            CGSizeMake(cropBox.size.height, cropBox.size.width), NO, resolution / 72); 
    }
 
    CGContextRef imageContext = UIGraphicsGetCurrentContext();

The PDF page can now be rendered on image's graphic context. But this can be a complex task because of all possible page rotations and page CropBox positions. Lucky for us this has been already implemented in the renderPage:inContext: method developed in the article 'Display a PDF page on the iPhone and iPad'. It is a static method in PDFPageRenderer class and it takes care of all the complications related to coordinate systems and transformations.

1
    [PDFPageRenderer renderPage:page inContext:imageContext];

The page has been rendered, we can now use the image in the application.

1
2
    UIImage *pageImage = UIGraphicsGetImageFromCurrentImageContext();  	
    UIGraphicsEndImageContext();

The complete source code and test PDF files can be downloaded below.
I placed the code in the static method convertPDFPageToImage:withResolution: in the PDFPageConverter class, the method is used like this:

1
2
3
4
5
    CGPDFPageRef page = CGPDFDocumentGetPage(pdfDocument, 1);
 
    UIImage *pageImage = [PDFPageConverter convertPDFPageToImage:page withResolution:144];
    NSString *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:destinationPath];
    [UIImagePNGRepresentation(pageImage) writeToFile:pngPath atomically:YES];

Source code: PDFPageConverter.zip
PDF files: TestFiles.zip
[relatedPosts]

Comments (8) Trackbacks (1)
  1. What about converting an image to PDF?

  2. This was most helpful as we had a project that heavily relied on PDF to image conversions and vice versa. I wish I had run into your site earlier as it would have saved me countless amount of hours.

  3. This is a great example, really really helpful!
    However I’m run into several memory crashes trying to convert a pdf of 200 pages on my device (iPad 1) with a scale of 1.0.
    The conversion works for about 80-90 pages and then crashes. I’ve found that the problem are the autoreleased image retrieved from the current image context through the instruction UIImage *pageImage = UIGraphicsGetImageFromCurrentImageContext();
    It seems that they aren’t purged enough frequently from memory, so the autorelease pool grows and cause the crash.
    I’ve solved the problem by purging periodically the autorelease pool inside the code that cycle through the pdf pages. This is what I’ve done:

    #define kPdfPurgePageInterval 20

    + (void)createPngs:(CFURLRef)aPdfUrl withScale:(CGFloat)aScale {
    NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];

    NSUInteger numberOfPages = CGPDFDocumentGetNumberOfPages(aPdfRef);
    for (NSInteger i = 1; i <= numberOfPages; i++) {

    if (!(i % kPdfPurgePageInterval)) {
    [autoreleasePool release];
    autoreleasePool = [[NSAutoreleasePool alloc] init];
    }

    }

    [autoreleasePool release];

    }

    I hope this trick could be helpful!

  4. very useful..i’ll follow your blog from now

  5. Thanks…
    It is very helpful for my App…


Leave a comment