Printing / Converting UIWebView to PDF
Note: My solution isn’t perfect. It lacks crispness since the document is rendered at 72 ppi. You will also have to work with your HTML so that it doesn’t get cut off when going to a new page.
I had a client that requested printing in their iPad app, which is no problem now with iOS 4. The app was a set of forms with inputs like text fields, switches, etc. Pretty standard stuff. I decided the easy way with so much dynamic content was to render everything to HTML and use UIMarkupTextPrintFormatter. This would handle displaying text without calculating metrics on everything at the very least. Easy enough and it worked well. Then the client also wanted to be able to print to PDF and email the document. This is where the fun started.
I figured that I would be able to use the same UIMarkupTextPrintFormatter to generate out my PDF for me, after all it was a UIPrintFormatter subclass. UIPrintFormatter contains the method,
- (void)drawInRect:(CGRect)rect forPageAtIndex:(NSInteger)pageIndex. I played around and got nothing but blank pages. Even the pageCount property on my UIMarkupTextPrintFormatter was returning 0. After a bunch of Google searches I still kept coming back to the same question on StackOverflow. Which the answer seemed to suggest that nothing is drawn till the system takes over.
Next plan of action was to see if I could convert a UIWebView to PDF. I was brought back once again to another question on StackOverflow. Which technically works, but doesn’t really handle multiple pages. This is when I decided to roll my own solution.
First thing, I need my HTML, nothing fancy here just a NSString. Next I need to create a UIWebView and load it with my HTML string. I also need a UIWebViewDelegate. We are going to assume that we are printing on a 8.5” x 11” sheet of paper, using 1” margins all around. So
6.5 * 72 for width and
9 * 72 for height.
NSString *html = ...; UIWebView *webView = [[UIWebView alloc] initWithFrame: CGRectMake(0, 0, 6.5 * 72, 9 * 72)]; [webView setDelegate: self]; [webView loadHTMLString: html baseURL: nil];
I needed to make a UIWebViewDelegate because if we try to do anything with our UIWebView now, it would still be empty. The system needs to parse and render our HTML. Now we need to implement the
From here you can use our NSData object pdfData to save out to file, or perhaps in my case attach to an email.
Now as the note at the beginning of the post said, this isn’t an ideal solution. The generated content doesn’t look the best but it works. I could have done the better thing and drawn out all of my content using Core Graphics / Quartz.