Recently, I was working on an app where in the user had a provision to generate a pdf, view it, and even give a print using AirPrint.

So I digged in and started some research on the same. And this is what I found – There are two ways for generating a pdf.

1. The first way is to use Core Graphics methods to create a pdf graphics context, begin a page(s), end the page, and finally release the context. We can use the following Core Graphics methods:

  • CGContextRef CGPDFContextCreateWithURL(CFURLRef url, const CGRect *mediaBox, CFDictionaryRef auxiliaryInfo)
  • void CGContextBeginPage(CGContextRef c, const CGRect *mediaBox)
  • void CGContextEndPage(CGContextRef c)

2. The UIKit framework also provides provision to generate pdf content. You can check out this link.

I tried both the approaches, and on looking closely, I found that the Core Graphics methods in turn require CoreFoundation methods, which would further require lots of CFReleases and all CF stuff. But the UIKit methods are easier to implement. Moreover, if you are targeting ARC, you have to use __bridge or any such keyword related to Core Foundation, because ARC does not control CoreFoundation objects. So I’d personally prefer the methods provided by UIKit, unless there is a strong need to use the CoreGraphics approach, which till now I didn’t find.

So in this tutorial, we will follow the second approach, and generate a pdf, which will ultimately look like:

Finally generated PDF programmatically-  iPhone SDK

Though if any one is interested in the Core Graphics approach, do let me know, I’ll try posting on that!

So, let’s get started.
Bump  up your Xcode, and create a new project, and choose View Based Application from the project template. We name the project as PdfGenerationDemo. We create a button and attach an action to it.

And we write the following in our action method:

- (IBAction)generatePdfButtonPressed:(id)sender
{
    pageSize = CGSizeMake(612, 792);
    NSString *fileName = @"Demo.pdf";
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];
 
    [self generatePdfWithFilePath:pdfFileName];
}

Here, we call our method, which will do the pdf generation stuff.

So, let’s go to this method. We have this code in this method.

- (void) generatePdfWithFilePath: (NSString *)thefilePath
{
    UIGraphicsBeginPDFContextToFile(thefilePath, CGRectZero, nil);
 
    NSInteger currentPage = 0;
    BOOL done = NO;
    do
    {
        // Mark the beginning of a new page.
        UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, pageSize.width, pageSize.height), nil);
 
        // Draw a page number at the bottom of each page.
        currentPage++;
        [self drawPageNumber:currentPage];
 
        //Draw a border for each page.
        [self drawBorder];
 
        //Draw text fo our header.
        [self drawHeader];
 
        //Draw a line below the header.
        [self drawLine];
 
        //Draw some text for the page.
        [self drawText];
 
        //Draw an image
        [self drawImage];
        done = YES;
    }
    while (!done);
 
    // Close the PDF context and write the contents out.
    UIGraphicsEndPDFContext();
}

Basically, we have two methods to create a pdf context:

1. void UIGraphicsBeginPDFContextToData (NSMutableData *data, CGRect bounds, NSDictionary *documentInfo)

2. BOOL UIGraphicsBeginPDFContextToFile (NSString *path, CGRect bounds, NSDictionary *documentInfo)

If we use the first method, the destination will be an NSMutableData. And if we use the second method, the destination is a file.

In our case, we use the second method, because we want to create a pdf file. This method takes three arguments. For the first, we give a path where our pdf will be generated.

Then we give our page size. Specifying an empty rectangle (CGRectZero) sets the default page size to 8.5 by 11 inches (612 by 792 points).

Lastly, we have a documentInfo dictionary, where we pass in nil. Here, we can specify additional metadata and security information for the PDF, such as the author of the PDF or the password for accessing it.

So till now, we have created our pdf context, and given the default page. We now need to start a new page for our pdf. We use the method:

UIGraphicsBeginPDFPageWithInfo(CGRectMake(CGRect bounds, NSDictionary *pageInfo);

The bounds specify the size and location of our new page. We specify a rect starting at point (0,0) and having a size of 612*792 pixels.

pageInfo is a dictionary to specify additional information regarding the page. We specify nil here.

Next, we call methods to draw a page number, border, header, line, text and an image. I will post the source code for this tutorial and you can catch all those methods there!

Basically, we are doing 4 main things, and these are usually the main things we require in a pdf.

Please note that we can use Core Graphics or Core Text to render our content.

These are:

1. Drawing a border.

2. Drawing lines.

3. Drawing text.

4. Drawing an image.

So let’s see how we do all these.

1. Drawing a border: 

- (void) drawBorder
{
    CGContextRef    currentContext = UIGraphicsGetCurrentContext();
    UIColor *borderColor = [UIColor brownColor];
    CGRect rectFrame = CGRectMake(kBorderInset, kBorderInset, pageSize.width-kBorderInset*2, pageSize.height-kBorderInset*2);
    CGContextSetStrokeColorWithColor(currentContext, borderColor.CGColor);
    CGContextSetLineWidth(currentContext, kBorderWidth);
    CGContextStrokeRect(currentContext, rectFrame);
}

Here, we just get the current context, select a color for the border, specify a rect for the border, which has an inset of 20 pixels, and then just stroke the rect using normal Core Graphics.

2.   Drawing lines:

- (void) drawLine
{
    CGContextRef    currentContext = UIGraphicsGetCurrentContext();
 
    CGContextSetLineWidth(currentContext, kLineWidth);
 
    CGContextSetStrokeColorWithColor(currentContext, [UIColor blueColor].CGColor);
 
    CGPoint startPoint = CGPointMake(kMarginInset + kBorderInset, kMarginInset + kBorderInset + 40.0);
    CGPoint endPoint = CGPointMake(pageSize.width - 2*kMarginInset -2*kBorderInset, kMarginInset + kBorderInset + 40.0);
 
    CGContextBeginPath(currentContext);
    CGContextMoveToPoint(currentContext, startPoint.x, startPoint.y);
    CGContextAddLineToPoint(currentContext, endPoint.x, endPoint.y);
 
    CGContextClosePath(currentContext);
    CGContextDrawPath(currentContext, kCGPathFillStroke);
}

Here too, we get the current context, set the line width and stroke color, specify the start and end points, move to the start point, add a line to the end point, and finally draw the path.

3. Drawing text:

- (void) drawText
{
    CGContextRef    currentContext = UIGraphicsGetCurrentContext();
    CGContextSetRGBFillColor(currentContext, 0.0, 0.0, 0.0, 1.0);
 
    NSString *textToDraw = @"Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
 
    UIFont *font = [UIFont systemFontOfSize:14.0];
 
    CGSize stringSize = [textToDraw sizeWithFont:font
                               constrainedToSize:CGSizeMake(pageSize.width - 2*kBorderInset-2*kMarginInset, pageSize.height - 2*kBorderInset - 2*kMarginInset)
                                   lineBreakMode:UILineBreakModeWordWrap];
 
    CGRect renderingRect = CGRectMake(kBorderInset + kMarginInset, kBorderInset + kMarginInset + 50.0, pageSize.width - 2*kBorderInset - 2*kMarginInset, stringSize.height);
 
    [textToDraw drawInRect:renderingRect
                  withFont:font
             lineBreakMode:UILineBreakModeWordWrap
                 alignment:UITextAlignmentLeft];
}

Here, we first calculate the size of the string we need to draw. We use the method sizeWithFont: constrainedToSize: lineBreakMode:. We give the font we desire. Then we give the argument for constrainedToSize. This is the rect that we want to constrain our string to i.e. the calculated string rect would not increase the value we provide for this argument. Here, we give the page size minus the border inset minus the margin inset, the margin inset being the inset between the border and the point at which we want to start our text. The lineBreakMode we give is UILineBreakModeWordWrap.

This method will return the bounding rect for our string i.e. it will automatically calculate the rect for our given string according to the font size we have given, constraining it to the size we have given for the constrainedToSize argument. This point is really important. Here, according to our business logic, we might even have a string that returns a rect that is more than the constrainedToSize value we have given. In that case, we might have to break our string two that it can fit into the rect in constrainedToSize method.

At last, we use NSString’s drawInRect: withFont: LineBreakMode: alignment: to draw our string into the rect we had earlier calculated for our string.

4. Drawing an image: 

- (void) drawImage
{
    UIImage * demoImage = [UIImage imageNamed:@"demo.png"];
    [demoImage drawInRect:CGRectMake( (pageSize.width - demoImage.size.width/2)/2, 350, demoImage.size.width/2, demoImage.size.height/2)];
}

Here too, we use UIImage’s drawInRect: method to draw the image to our context, passing in the rect in which to render our image.

And finally doing all our pdf generation stuff, we close our context by calling UIGraphicsEndPDFContext() method.

Quick Tip: We can  even generate a multi page pdf- All we need to do is take a variable, and while rendering content, update that variable. If our vertical height is equal to the height of our page, we can increment the pageNumber, and start a new page. Here, for demo purposes, we are just generating a single page pdf.

As usual, you can grab the source code for the demo - PdfGenerationDemo iPhone.

An Update:  

I received some mails, and comments on where the generated pdf is. To check how our pdf looks like, we have to open the documents directory, coz we have given the location of our pdf in the documents directory. I have given a detailed explanation on where to find the documents directory for the application in this tutorial:
http://www.ioslearner.com/convert-html-uiwebview-pdf-iphone-ipad

Happy Coding :)

  58 Responses to “Generate PDF programmatically in iPhone/iPad SDK”

  1. Hi,
    great tutorial…. I could even generate a multipage pdf.
    I’ve a problem in justifying the text. there are no options in UITextAlignment. Please help me

    Thanks in advance

    • Hi Nagaraj, according to iOSLearner’s code, when I want to create a multi-page PDF, I’ll check condition as follow:

      If (stringSize.height >= renderingRect.size.height) {
      //code to split text into parts
      }

      But how can I split text into parts. Thanks.

  2. Hi Nagaraj, How exactly you want to justify the text? If you want to specify how the text needs to be aligned, there are 3 options, UITextAlignmentLeft, UITextAlignmentCenter andUITextAlignmentRight. These can be used. In the “drawText” method, you can specify UITextAlignmentRight, and note the difference.

    • Hi,

      Excellent post by the way

      I have editable text and an UIWEBVIEW(where in the URL changes), but it all gets displayed in one page

      How can i split it into different pages.

      Thanks,
      Harsha vardhan

  3. Hi,
    Thanks for the reply. I want ‘justified text alignment’ which is not provided by apple as of now.

  4. how can i write html into pdf?

  5. I have not tried writing an html into a pdf. But, the option that seems feasible to me is to write the html into a UIWebview, and then write the web view into the pdf context. Hope that helps. I will try posting on this, once i get time.

  6. Hi

    great tutorial…. but perhaps I am very stupid. After pressing the button there is no pdf file or preview or something like that. Do I something wrong??
    Happy new year by the way.

    • Hi Rene. The pdf will be saved in the documents directory. It will be in this location: /Users/”Username”/Library/Application Support/iPhone Simulator/”Your App Directory”. Hope that helps.

  7. Excellent tutorial, thanks!

    • Thanks Paul. Feel free to suggest a tutorial you want for a particular topic. I will try posting.

      • hi!!! all frnds i recently joined iphone develoment before 1 month ago and i got a project based on PDF Reader application. the project is about to read the document and display images and videos in the iphone can anyone help me guys!!….i am waiting for your valuable reply guys …..once again request….from all of you… pls contact me through my mail..id:
        shivpandey999@gmail.com

  8. Hi,

    After clicking on button, I am not able to find the pdf file.
    I was not able to fnd the location :/Users/”Username”/Library/Application Support/iPhone Simulator/”Your App Directory”
    Can u suggest where can I find the pdf location or change the location of pdf file?

  9. Hi Chirag. Which OS are you using? In Snow Leopard, the documents directory is the one I have mentioned. That is, from your root folder, go to your username directory, then application support, from there, go to the iPhone Simulator directory, from there, you can find your application’s documents directory. In Lion, the Library folder is there but it is hidden. Just click on the username directory, Then Go -> Go to Folder, and type in Library, the Library folder will be unhidden. Then follow the same directory structure.

  10. Hi,

    I tried that too , but in Lion, username directory there is no folder directory and hence cannot find library folder. But it worked in UIWebview.
    There is one more doubt, in drawtext function, you have used NSString *textToDraw, but i want to know whether I can used NSArray (i.e fetch data from NSArray).
    Can you give some idea or snippet code.

    Thanks

  11. Chirag, this was just a demo code. To use it, you have to modify it according to your requirements. Like, just update the drawText method, to look something like:
    drawText: (NSString *)textToDraw inRect: (CGRect)renderingRect
    {
    CGContextRef currentContext = UIGraphicsGetCurrentContext();
    CGContextSetRGBFillColor(currentContext, 0.0, 0.0, 0.0, 1.0);

    UIFont *font = [UIFont systemFontOfSize:14.0];

    [textToDraw drawInRect:renderingRect
    withFont:font
    lineBreakMode:UILineBreakModeWordWrap
    alignment:UITextAlignmentLeft];

    }

    Now, just loop over your array and call this method for every NSString in that array, passing in the text and the rect in which to render the text.
    Again, this is a general solution, in the end, it all depends on the requirements, when you are dealing with Core Graphics.

  12. Thanks for the help. It worked with an array.

  13. Hey, Thanks for the tutorial.
    How can I attach this pdf with email as an attachment? Also, how can I change the location for downloaded pdf in the xcode

  14. Hey, Thanks for the tutorial.
    How can I attach this pdf with email as an attachment? Also, how can I change the location for downloaded pdf in the xcode.

    • James, to attach the pdf as a mail, you can use:

      MFMailComposeViewController’s – (void)addAttachmentData:(NSData *)attachment mimeType:(NSString *)mimeType fileName:(NSString *)filename.

      Give the mimeType as application/pdf. Pass in the data as your pdf data. Hope that helps.

  15. Hi, can you make a tutorial / demo on how to generate a multi-page PDF from HTML.
    Thanks in advance.

  16. Hi nvhieu, I will post a tutorial on generating a pdf from an HTML! I am a bit busy with some assignments. Will post as soon as i get time. Stay tuned.

  17. Finally! I have been wanting to generate PDF’s from the iphone and every tut I find is overly difficult. At first I was getting lost as I did not see the header info and did not know what ‘pageSize = CGSizeMake();’ was? At the end I found the link to the file. I pretty much copy pasted everything but it worked right away. Another user asked how to find the file generated and there it was. It is still a bit over whelming to look at the whole thing but now I have working code that I can analyze and see how it breaks down and works!

    Awesome!
    Thanks!!!

  18. Hi,
    I’ve knew how to create multipages PDF, but I got probem with a-very-long text. How can I split text into part to draw in PDF pages? How can I know when the text fill the page rect and where is the position of text to start a new page?
    Thanks so much.

  19. This is an excellent post, your efforts to share this step by step are to be commended! Is it possible that you could share how to take a UIWebview that is being displayed and write it to file in PDF format?

    Currently I populate a UIWebview with “NSString stringWithFormat” and then write it to disk using [myHTML writeToFile:htmlFilePath atomically:YES encoding:NSUTF8StringEncoding error:&err];

    I would like to save it as a PDF using your method, could you possibly help me with this?

    Again, awesome tutorial!

    • Thanks dcinqc. Surely I will help you with this. I have already got a lot of requests on writing an html to pdf. The next blog that comes up will be on that. Stay tuned!

  20. Thank you so much for the great post.

    I would love to see sample code on how to handle Multiple Pages PDF. Also if you have the source text as HTML code, is there a way to convert it to PDF?

  21. To enable multi-paging in a pdf, you need to calculate the height of every string you render, and you also have to store the vertical height (the y distance of the page from the top that has already been used), and every time you render a string/image, you have to update the vertical height. Once your vertical height reaches a threshold, i.e. the height of your page, you have to start a new page, and reset the vertical height to 0. And repeat the whole process again.
    Hope that helps. Regarding converting an HTML into a pdf, I will be posting a tutorial on that shortly. A bit busy with assignments, so I am not getting time these days :(

    • Thanks for the tip and I look forward to your next tutorial on HTML to PDF. I hope you get all of your assignments done :)

  22. Thanks. Went through the Apple docs, some other sources, ended up with odd mixed results, now I’m up and running good.

    For printing through my app decided that printing all to a PDF file first then submitting to the print controller was a better alternative and the bonus being that the user can now either save to PDF or just print.

    Good stuff!

  23. hi!!!
    all frnds i recently joined Iphone Development before 1 month ago and i got a project based on PDF Reader application. the project is about to read the document and display images and videos in the Iphone can anyone help me guys!!….i am waiting for your valuable reply guys …..once again request….from all of you… pls contact me through my mail..id:
    shivpandey999@gmail.com

  24. hey john please help me

  25. Thank you so much for a great tutorial that even a newbie like me could follow. Your relevant choice of topic really helped me out at the perfect time!

  26. Hi,

    I am a newbie and trying to learn iOS. This seems to look good but when I clicked Generate Pdf button..nothing happens. :(
    Please help me out.

    Regards,
    Dave

  27. Hi Dave, I have updated the post to locate the pdf. It gets saved in the documents directory. Hope that helps!

    • Hello~

      Thanks very much for your tutorial. It’s great!! Now I can create a PDF file.

      Could you please teach me how to email with a PDF as its attachment?

      In earlier replies, you wrote:

      MFMailComposeViewController’s – (void)addAttachmentData:(NSData *)attachment mimeType:(NSString *)mimeType fileName:(NSString *)filename.

      Give the mimeType as application/pdf. Pass in the data as your pdf data. Hope that helps.”

      However, I still don’t know what to put in the field of NSData. I tried to put nil. But that gave me a email without attachment.

      Thanks very much for your help in advance!

  28. [...] our previous tutorial, we had generated a pdf programmatically on iPhone. I got loads of requests for a tutorial to [...]

  29. I’m new so forgive so please forgive my question if it sounds dumb. Does this cause any type of memory issue? For example, if I create it to email out as a PDF I don’t want it to be stored . I see it stored in the /library on the computer simulator & Im thinking it’ll save on the iPhone or within the app I create . Thanks! :)

  30. sorry for the typo’s before :)

  31. Hi Richie. Yes you are right. The pdf will take memory of the iPhone. Though it does not make much difference. But, if the pdf you are generating is really heavy, you can delete the file, after you have used it. It can be done using NSFileManager:
    [[NSFileManager defaultManager] removeItemAtPath: filePath error: &error];
    Hope that helps!

  32. How to edit an existing PDF & then re-save it. Thanks in advance.

  33. Hello,

    Thanks very much for your good tutorial. It’s great!! Now I can create a PDF file by using UIKit Framework .
    Can you provide me some tutorial for doing this by using Core Graphics approach .
    Please reply me ASAP

    Thanks very much for your help in advance!
    Pooja Rusia

  34. It’s awasome guides with tutorial…Thanks..

  35. its good tutorial.
    how to set color in particular string text in pdf.

    for example in your tutorial
    how to set color for only apply word

    draw text

    textview.text=@”apple”;
    nsstring *textToDraw =[NSString stringwithformate:@"This %@ good",textview.text];
    UIFont *font = [UIFont systemFontOfSize:14.0];

    CGSize stringSize = [textToDraw sizeWithFont:font
    constrainedToSize:CGSizeMake(pageSize.width - 2*kBorderInset-2*kMarginInset, pageSize.height - 2*kBorderInset - 2*kMarginInset)
    lineBreakMode:UILineBreakModeWordWrap];

    CGRect renderingRect = CGRectMake(kBorderInset + kMarginInset, kBorderInset + kMarginInset + 50.0, pageSize.width – 2*kBorderInset – 2*kMarginInset, stringSize.height);

    [textToDraw drawInRect:renderingRect
    withFont:font
    lineBreakMode:UILineBreakModeWordWrap
    alignment:UITextAlignmentLeft];

  36. Hi , really its a great tutorial. It helped me a lot. But, I want to display the contents of pdf in a view controller. How could i do that. ? Can Any one help me please… I am new to pdf development…

    Thanks in advance…

  37. sorry i mean to say in another view….

  38. Hey thanks for this tutorial ,

    Here i have a question ,
    I have 4 uiviewcontroller is this possible to save them in one pdf file ?
    Would you please explain how to save longer uiviewcontroller in PDF ?

    Thanks in Advance.

  39. The code is successfully run in Simulator… but were the Save “pdf” file will be store, Plz any one can reply me…

  40. In your drawText method how would you go about rotating the text 90 degrees? I have tried using drawAtPoint which allows for the rotation….but I lose the bounding rectangle when using drawInRect :-(

  41. Hi,

    first thanks for the tutorial – I got it working with multi-paging of String-Arrays when I discovered a problem.

    Some of my Strings are “larger” than 1 page, so I would have to rip the String apart, print the first part on e.g. page 1 and the rest on page 2.

    Maybe someone got an idea :/

    Thanks,
    Wisi

  42. Thanks for your post. How can we make the generated pdf non editable (locked) ? PDF can be altered using a tool that can edit the PDF.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>