The iOS SDK offers two venues for creating PDF files: UIKit or the Core Graphics. With either of these paths you can create one page or loop over the content and create multiple pages. These drawn PDF pages can include custom formatting, images, borders and page numbers to name a few. But you are only limited by your own imagination and the time allowed for the project or the requirements or a combination of any of these to produce beautiful looking PDF documents that can be printed or stored in iCloud, Dropbox or Google Drive for example.
In this tutorial I will review the PDF creation lifecycle and I will build a simple iOS iPhone app to capture text from an UITextView and save that content to a PDF file using the UIGraphicsBeginPDFContextToFile and some classes from the Core Text framework. Finally I will walk you through the code.The UIKit has two methods for creating PDF documents: UIGraphicsBeginPDFContextToData and UIGraphicsBeginPDFContextToFile. The first will draw PDF content on a page that will be stored in a NSMutableData.
The process of creating PDF documents that draws content on the page is very straightforward. First you need to set the page size and create the PDF Graphic context with the UIGraphicsBeginPDFContextToFile method. To set the page dimensions, you can user the CGRect class and the CFRange class in the Core Foundation framework. Render the contents on the page by first marking the beginning of the page using the UIGraphicsBeginPDFPageWithInfo function. Once the PDF drawing process is complete, you need to call the UIGraphicsEndPDFContext to close the file saving the the contents in the PDF file. The lifecycle is presented in the following screenshot.
Develop the Application : Storyboard
To demonstrate how to create PDF documents using the functions in the UIKit, I will create a Single View application using the provided template in Xcode. You may opt to use a xib file to setup your user interface (GUI) in the Interface Builder (IB), I am suggesting to leave the xib option unchecked and Xcode will create a storyboard instead. I prefer working with storyboards because you to build your complete UI workflow in one screen. This is pretty unique amongst IDEs and development platforms. You can name your app anything you like, however I will name mine “PDF Creator”. Once the app is loaded in Xcode IDE, open the storyboard add:
- An UITextField and corresponding UILabel,
- then add an UITextView and corresponding UILabel, finally
- add an UIButton and change the front facing label to “Create PDF”
The following screenshot provides a visual of this simple UI. Next I will create IBOutlets and IBAction for these visual controls in the associated header file.
To create the IBOutlets and IBAction, click on the Editor assistant icon in the toolbar menu (it is the one that looks either like a face or a tuxedo depending how you process images). The header file of the custom view controller class as defined in the “Identity inspector” (it is the third icon from the left in the utilities window on the right. If it is not open, click on the “Show utilities” icon in the toolbar. It is the one before the Organizer icon). Using the keyboard and the mouse, select the UITextField and control + drag a connection line from the UITextField to the open header file. Releasing the buttons will trigger Xcode to produce a popover, allowing you to define a name for the IBOutlet, like “enterSubject” which I will use for the filename. The remaining options, like the connection type, will remain the same. the following screenshot provides a visual on the process.
Repeat the process for the UITextView, naming the connection “enterText”. When creating a connection for the UIButton which will be an IBAction, change the connection type in the popover to “Action”. I will call this IBAction, createPDF. Xcode will create the correponding method in the header and add the method template to the implementation. To complete the UI, drag a connection from both the UITextField and the UITextView to the proxy icon at the bottom of the View Controller and select “delegate” from the popover. We will need this call the textFieldShouldReturn to dismiss the keyboard after editing the UITextField.
Develop the PDF Processing Logic
The final part of the app is to add logic to the header and implementation files of the ViewController custom class to grab the text from the fields in the storyboard to create a PDF file.
Open the header file and add two extra instance methods to draw the page number on each page of the PDF and to draw the text on the each page of the PDF as required. For the page number, define the drawPageNbr method with one argument of type int called pageNumber. The second method will be called updatePDFPage and it will have two arguments, setTextRange which will be the text from the UITextView and the setFramesetter to set the text in a frame on the page, sort of like a layout manager. The code is provided below.
In the implementation file the method to look at is the textFieldShouldReturn. This method is called by the UITextField delegate to dismiss the keyboard when the “Return” is pressed on the keyboard. In the method’s body, the code checks to see if the caller is the enterSubject UITextField and calls the resignFirstResponder if it is.
The second method that is needed to dismiss the keyboard is textView :shouldChangeTextInRange:replacementText. This method is called by the UITextView by its delegate in a similar fashion.
Next we will discuss the createPDF IBAction method that we created earlier. Since we need to save the PDF files to the Documents directory in the application’s sandbox, we will first get a handle on the Documents path using the NSSearchPathForDirectoriesInDomains and passing in the NSDocumentDirectory constant for the Documents directory. This will return an array of directories which will be used to get the top element of the array with the objectAtIndex:0 for the top level Documents directory. Next append the name of the of the file which will come from the enterSubject UITextField. Then create the frame for the text from the UITextView using the CFAttributedStringRef that will setup the CFString using the CFAttributedStringCreate function. This is to convert the NSString to the CFString to be used by the Core Foundation class. Notice the __bridge directive which is used in conjunction with ARC to provide a casting between the string object the core foundation function.
If this goes according to plan. setup the framesetter object using the CTFramesetterCreateWithAttributedString function and begin the PDF creation process by defining a PDF context with the UIGraphicsBeginPDFContextToFile passing it the value documentPath to create the initial PDF file on the file system.
Then add a page to the file using the UIGraphicsBeginPDFPageWithInfo method. Set the size of the page to 612x792. Then set the page number and call the drawPageNbr to draw the page number, defined by currentPage int variable which will be increment with each iteration of the do loop. Then following the PDF creation lifecycle, add the text that we set in the framesetter earlier to the page using the updatePDFPage method. I will describe this method next after this one method. If we have reach the end of the text, set the done variable and exit the loop and call the UIGraphicsEndPDFContext to close the PDF context. Finally release the Core Foundation CTFramesetterRef since ARC doesn’t manage the Core Text classes like Core Foundation.
The drawPageNbr method first sets the string and page number that will be drawn at the bottom of the page. The next line of code establishes the font of 10 pts. Then we set the total size of the area where the page number will be drawn, which our case is 612x72. The pageStringSize will contain the maximum size of the page number string will be drawn by determining which font to use and calculating the size constraints with constrainedBySize, which is the bounds of the maxSize rectangle and also sets the line break mode to use. This will be used next in the stringRect variable to establish the size of the rectangle to use and its placement on the page. The final statement actual draws the page number on the page
ViewController.m - drawPageNbr
ViewController.m - updatePDFPage
This last method will draw the content of the UITextView in the rectangle of the PDF page. First we get a handle on the graphics context that we are using. Then set the rectangle size for the text that will be use by the frame. The frameset will set the bounds of the text layout. The CGPathCreateMutable create a graphics path which represents a series of lines and shapes. These two preceding variables will then be used to create the rectangle for the text with the CGPathAddRect function.
The CTFramesetterCreateFrame function uses the text and framesetter to layout the content in the frame. The CGContextTranslateCTM and CGContextScaleCTM functions position the text within the frame and the CTFrameDraw draws the text in the frame. The CTFrameGetVisibleStringRange returns the number of characters that fit in a frame and the characters that don’t fit one frame can be moved to another frame. This is it. This code, presented below, offers one of several ways of creating PDFs, even within the UIKit framework and Core Graphics. The use of the Core Text is optional but essential for this example.
ViewController.m - updatePDFPage
This article is accurate and true to the best of the author’s knowledge. Content is for informational or entertainment purposes only and does not substitute for personal counsel or professional advice in business, financial, legal, or technical matters.
© 2012 Kevin Languedoc
tejal on August 01, 2018:
hello i m having problem in creating pdf in swift 10.3 ios i m using it in 11.0 ios but for lower versions pdf kit is not working so what could be done if i have to convert the image into pdf and display it in view in pdf format
Nagurbee on June 14, 2018:
I am using the above code it's creating the document not pdf file
Can you please help me the how to create PDF file and send this PDF file to email.. Thanks in advance
Create Custom PDF on August 09, 2017:
Can you help me how I can create custom PDD which includes Header, Footer, Tableview Data, List Type Data and watermark image also need Index.
Please help me.
Waaheeda Wahida on March 27, 2017:
very nice!! it helped me !! thanks
Kevin Languedoc (author) from Canada on March 26, 2016:
If I understand correctly, you would like to save all data from table to pdf? I can help with this
Sorry I don't have any code at the moment to help you out.
Rendering a pdf in a browser (webview) is very much dependent on the browser the end user is using and not the webview itself.
Ryan on February 16, 2016:
Hello Kevin, I have a quick question. I have a textView with long content on my viewcontroller. It is about 4 pages long. I have two problems.
1) Having a problem with converting obj-c to swift. Do you have swift code for this tutorial?
2) Which part is making sure that it correctly renders all pages of textview??
Bikram on February 13, 2016:
Hello Klanguedoc. Thanks for your response. I can understand that how I can make PDF format as like table and how I can save all values according to table coloums and row. Please if you have any tutorials and anything else she with me thanks a lot....
Kevin Languedoc (author) from Canada on February 13, 2016:
You need to use the data source of the UItableview and not the table view itself as the source for your pdf. If your data source is a nsarray, etc. Then this is the data that you can save as pdf
Bikram on February 13, 2016:
Hello Kevin, Thanks a lot for great toturials. It is very helpful for me. But I can't understand how I can save whole tableview data into PDF file. Please help me. Thanks and Regards...
Kevin Languedoc (author) from Canada on May 26, 2015:
Sorry but I don't have the source code. I lost the code when the HDD went down and I thought I had a backup but I don't. Sorry.
Is the Context (current session) set correctly. Also what iOS version are you using
Geo on May 25, 2015:
Can you put the source code,please ? i get this :CGContextScaleCTM: invalid context 0x0. and nothing is happen when create pdf is pressed
Kevin Languedoc (author) from Canada on March 31, 2015:
Please check out my other tutorials that explain how to do this
Pradeep on March 30, 2015:
I am new to iOS development.i made registration page.and also use validation i want to our name,pas textfiled and also use picker view for male and feamle for catogry.i want to all data send in one view to another view and also print data in tableview.please help me how to make this
Kevin Languedoc (author) from Canada on July 29, 2014:
you can get the source at www.iosdev101.com/downloads
B Bhangu on July 29, 2014:
HIII how can i download source code of this?
Kevin Languedoc (author) from Canada on June 08, 2014:
If you are using images in your files, you might consider compressing the images first.
you can get all source at www.iosdev101.com/downloads
iyke okeke on June 07, 2014:
Thanks for the tutorial but is there a way to download this source files. Can't really see it there.And another thing, the area where you added the do/while is generating error.
harsh on June 03, 2014:
thanks for tutorial ,but it take too much memory can we compress the result pdf file ??
mjacobs on December 17, 2013:
That's Awesome! A huge help. I've searching the web for an update for that code since I posted 11 hours ago! I can wait and save my sanity!
Your the Man!
Kevin Languedoc (author) from Canada on December 17, 2013:
Sure thing. I will update by sunday 12/22/2013. Hope this is ok.
mjacobs on December 17, 2013:
Thanks for the great tutorial. I tried running this and found that some of the code was a little old (it stated it was depricated in iOS 7). Is there any way you can update the code?
Kevin Languedoc (author) from Canada on June 14, 2013:
For the photo, you will need to use UIImage and NSData to convert image to binary. For the UILineBreakClip, use the NSLineBreakMode instead.
jfellows123 on June 07, 2013:
My apologies. The code works. I forgot to create the delegate connections for the TextField. However, I am getting a warning that "UILineBreakClip is depreciated: first deprecated in iOS 6.0" in the drawPageNbr section. Can you suggest a fix for this? Also I'd like to add a photo to this and be able to print it out. Any suggestions much appreciated. Jack
jfellows123 on June 07, 2013:
First, I would like to thank you for you very thoughtful tutorials. I'm a new coder, and have found them invaluable. I'm wondering about this iOS Create PDF using UIKit. Is there some code missing? It seems like the code related to ":shouldChangeTextInRange:replacementText" is missing. When you run this as is, the keyboard won't retract. Would it be possible to get an update with that code or the code itself. I'm really tying to learn how to create, view, and print out PDFs from a view of text and images (like a photo album). All the code examples I have found are done with xib. My project is developed with storyboards, and I can't seem to convert the xib to storyboards. Your's was the first storyboard version I have found. Still looking for storyboard PDF viewing and printing examples. Any help would be appreciated. Jack
Kevin Languedoc (author) from Canada on April 26, 2013:
Mini, it's all there in the API. Yes you can add images. It is basically drawing and layout your page.
brunohdc on April 19, 2013:
Thank for your tutorial, its very useful to me.
mini on March 19, 2013:
Nice tutorial ,Thanks ...How easy it is to add images on top of this PDF and do operations like rotate ,scale on them ?
Kevin Languedoc (author) from Canada on December 18, 2012:
hope it helps
Iva on December 17, 2012:
Thank you for your answer, Kevin!
Kevin Languedoc (author) from Canada on December 17, 2012:
Yes, a UITableView is only a data display for its data source, so to create a PDF from data displayed in an UTableView in whole or in part, use the the data source. To create a PDF from selected data, use the UITableView delegate's method – tableView:didSelectRowAtIndexPath: and add the selected data to a new NSMutableArray
Iva on December 16, 2012:
Hallo Kevin, thank you for a great tutorial... Is it possible to create a PDF file from UITableView? Thank you, Iva