iPDFdev PDF development for iPhone and iPad

Convert an image to PDF on the iPhone and iPad

April 22nd, 2011

A reader asked a me about image to PDF conversion a few days ago and I promised him an article, so here it is.

Image to PDF conversion is based on Quartz API. Using Quartz we can create PDF files and add content to them, the conversion actually means drawing the image on a PDF page.

Let's begin.

First we compute the size of the PDF page. Based on the image size and the resolution we want to draw the image, the page size is computed like this (for flexibility different horizontal and vertical resolutions are supported):

1
2
    double pageWidth = image.size.width * image.scale * 72 / horzRes;
    double pageHeight = image.size.height * image.scale * 72 / vertRes;

Now we're ready to create the PDF file. It can be created directly on disk or in memory. For flexibility let's create it in memory.

1
2
3
4
5
6
    NSMutableData *pdfFile = [[NSMutableData alloc] init];
    CGDataConsumerRef pdfConsumer = 
        CGDataConsumerCreateWithCFData((CFMutableDataRef)pdfFile);
    // The page size matches the image, no white borders.
    CGRect mediaBox = CGRectMake(0, 0, pageWidth, pageHeight);
    CGContextRef pdfContext = CGPDFContextCreate(pdfConsumer, &mediaBox, NULL);

The PDF context is created, we can now perform the conversion:

1
2
3
    CGContextBeginPage(pdfContext, &mediaBox);
    CGContextDrawImage(pdfContext, mediaBox, [image CGImage]);
    CGContextEndPage(pdfContext);

The work is done, finalize the PDF file and release the used objects.

1
2
    CGContextRelease(pdfContext);
    CGDataConsumerRelease(pdfConsumer);

The PDF file is now available in the pdfFile variable.
I placed all the code above in the convertImageToPDF:withHorizontalResolution:verticalResolution: static method in the PDFImageConverter utility class, it can be used like this:

1
2
3
4
    NSData *pdfData = [PDFImageConverter convertImageToPDF: image 
        withHorizontalResolution: 300 verticalResolution: 300];
    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent: @"Documents/image.pdf"];
    [pdfData writeToFile:path atomically:NO];

Sometimes it is necessary to convert an image to PDF and use a predefined page size, such as Letter or A4. Also a maximum bounding rectangle can be specified for the image, so it is placed at a specific position on the page and it does not get out of the page. In this situation the image size must be adjusted (increased resolution) to make sure the image fits the given rectangle.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    double imageWidth = image.size.width * image.scale * 72 / resolution;
    double imageHeight = image.size.height * image.scale * 72 / resolution;
 
    double sx = imageWidth / boundsRect.size.width;
    double sy = imageHeight / boundsRect.size.height;
 
    // At least one image edge is larger than maxBoundsRect, reduce its size.
    if ((sx > 1) || (sy > 1)) {
        double maxScale = sx > sy ? sx : sy;
        imageWidth = imageWidth / maxScale;
        imageHeight = imageHeight / maxScale;
    }
 
    // Put the image in the top left corner of the bounding rectangle
    CGRect imageBox = CGRectMake(
        boundsRect.origin.x, boundsRect.origin.y + boundsRect.size.height - imageHeight, 
        imageWidth, imageHeight);

Having the final box, the image can be converted to PDF using the code in the first half of the article.
The code for the new conversion method is placed in the convertImageToPDF:withResolution:maxBoundsRect:pageSize: static method in the PDFImageConverter utility class, it is used like this:

1
2
3
4
5
6
7
8
    CGSize pageSize = CGSizeMake(612, 792);
    CGRect imageBoundsRect = CGRectMake(50, 50, 512, 692);
 
    NSData *pdfData = [PDFImageConverter convertImageToPDF: image 
        withResolution: 300 maxBoundsRect: imageBoundsRect pageSize: pageSize];
 
    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent: @"Documents/image.pdf"];
    [pdfData writeToFile:path atomically:NO];


Source code: PDFImageConverter.zip

Related Posts:

Comments (30) Trackbacks (1)
  1. It would be possible to add a digital signature (certificate, hash, etc) to a PDF on the iPhone?

    Congratulations on the blog

    • Current PDF API in iOS does not support adding new objects in a PDF file, such as digital signatures, annotations, etc. Let’s hope this will be fixed in iOS 5 :)

  2. If I convert a PDF page to image, add some ink to it, and convert the image back to PDF, will it grow in size substantially? Is there an easy way to replace this new page in the original PDF document?

    • The growth in size depends on the source PDF page. It is text and image based, the growth in size can be significant. If you convert the page to image at a lower resolution to get a smaller image, when you create the new page from the image it will look pixelated. If you convert the page to image at a higher resolution you will have an image with a higher quality but also greater size. I recommend to add the ink directly to the existing PDF page. You can create a CGPDFDocumentRef from your original PDF file, update the document’s pages and then save the new document.

  3. We’re trying to save the ink in a separate context and send it up to the server with a document id where it will be combined with the original document. How can we determine what page of the PDF document the user is viewing?

  4. Thank you for your article. This works perfectly.But I am trying to convert tiff images to pdf. Actually it converts the first page of tiff images to pdf. Do you know how to convert multi-paged tiff images to pdf ?

  5. Thanks for this great post! I’m trying to take an image from the device’s camera and convert it to PDF. I’m using this method to grab the image and convert it with your class:

    - (void)imagePickerController:(UIImagePickerController *)picker
    didFinishPickingMediaWithInfo:(NSDictionary *)info
    {
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];

    NSData *pdfData = [PDFImageConverter convertImageToPDF: image
    withHorizontalResolution: 300 verticalResolution: 300];

    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent: @"Documents/new.pdf"];
    [pdfData writeToFile:path atomically:NO];
    }

    The issue is the image is saved rotated and it looks distorted. It works fine with any image that is not taken from the camera. Any ideas?

  6. Can i use this code to convert SVG images to PDF .

  7. Can you provide a code that converts SVG File to PDF.

  8. It’s a nice article. One thing what I observed was the UIImage will be converted to an image in PDF rather than actual PDF . Is there any way to convert it into actual PDF text.

  9. Very helpful post as I have posted this on our forum so other people can find out also on image to PDF creation

  10. Hi,

    How can i make multiple image into a single pdf. I tried ur code. but it works oly for 1 image. The image which i choose last alone appears in the pdf but i want all the images which i choose from the photo library to be displayed in the pdf. please help me

  11. I am also having difficulty saving multiple images as a single pdf. I loop through the images and apply the “begin”, “draw”, and “end” methods to each image, but the resulting pdf is only one of the images.

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    +(NSData*)convertArrayOfImagesToPDF: (NSArray*)theImages withResolution: (double)resolution {
    if (resolution <= 0) {
    return nil;
    }

    CGSize pageSize = CGSizeMake(612, 792);

    NSMutableData *pdfFile = [[NSMutableData alloc] init];
    CGDataConsumerRef pdfConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)pdfFile);

    // CGContextRef pdfContext = nil;

    for (int i=0; i 1) || (sy > 1)) {
    double maxScale = sx > sy ? sx : sy;
    imageWidth = imageWidth / maxScale;
    imageHeight = imageHeight / maxScale;
    }

    // Put the image in the top left corner of the bounding rectangle
    CGRect imageBox = CGRectMake(0, 0 + pageSize.height – imageHeight, imageWidth, imageHeight);

    CGRect mediaBox = CGRectMake(0, 0, pageSize.width, pageSize.height);
    CGContextRef pdfContext = CGPDFContextCreate(pdfConsumer, &mediaBox, NULL);

    CGContextBeginPage(pdfContext, &mediaBox);
    CGContextDrawImage(pdfContext, imageBox, [image CGImage]);
    CGContextEndPage(pdfContext);
    CGContextRelease(pdfContext);

    }

    CGDataConsumerRelease(pdfConsumer);

    return pdfFile;
    }

  12. Nevermind – I figured it out. Just needed a good night’s sleep :)

    Here’s is the method that will give multi-page pdf from an array of images, in case anyone else is interested:

    //Code added by Chris Ruddell
    ////////////////////////////////////
    +(NSData*)convertArrayOfImagesToPDF: (NSArray*)theImages withResolution: (double)resolution {
    if (resolution < = 0) {
    return nil;
    }

    CGSize pageSize = CGSizeMake(612, 792);

    NSMutableData *pdfFile = [[NSMutableData alloc] init];
    CGDataConsumerRef pdfConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)pdfFile);

    CGRect mediaBox = CGRectMake(0, 0, pageSize.width, pageSize.height);
    CGContextRef pdfContext = CGPDFContextCreate(pdfConsumer, &mediaBox, NULL);

    for (int i=0; i < theImages.count; i++) {
    double maxScale = sx > sy ? sx : sy;
    imageWidth = imageWidth / maxScale;
    imageHeight = imageHeight / maxScale;

    // Put the image in the top left corner of the bounding rectangle
    CGRect imageBox = CGRectMake(0, 0 + pageSize.height - imageHeight, imageWidth, imageHeight);

    UIImage* image = [theImages objectAtIndex: i];
    CGContextBeginPage(pdfContext, &mediaBox);
    CGContextDrawImage(pdfContext, imageBox, [image CGImage]);
    CGContextEndPage(pdfContext);
    }

    CGContextRelease(pdfContext);
    CGDataConsumerRelease(pdfConsumer);

    return pdfFile;
    }


Leave a comment