In this post we will learn on how to generate a pdf from an html file, or convert an html rendered in a UIWebView into a pdf.
Steps to convert html file to pdf
Step 1: Create a new project, and choose View Based Application from the project template. We will name our project “HtmlToPdfDemo”.
Step 2: Then add UIWebView into our HtmlToPdfDemoViewController.xib file. We will now create an outlet for our UIWebView, and write an action as follows:
#import <UIKit/UIKit.h>
@interface HtmlToPdfDemoViewController: UIViewController
{
UIWebView *webView;
}
@property (nonatomic,retain) IBOutlet UIWebView *webView;
- (IBAction) htmlToPdfButtonPressed:(id)sender;
@end
Step 3: Our initial project setup is complete, we will get started with pdf generation stuff. I have included a Demo.html file in the bundle, and we will convert this html into a pdf . For this we first load our webView in our viewDidLoad as follows.
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Demo" ofType:@"html"]];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[webView loadRequest:req];
}
Step 4: Our pdf converting code does not really belong in the HtmlToPdfDemoViewController, so let’s farm that off into a new UIViewController called HTMLtoPDF. Create a new file with the iOS\Cocoa Touch\Objective-C class template, enter HTMLtoPDF for the Class and UIViewController for the subclass, and finish creating the file. class implements UIWebViewDelegate
Let’s create a new method in the HTMLtoPDF.m file called createPDFWithHTML: and make it a static method. Also predeclare this method in HTMLtoPDF.h file.
+ (id)createPDFWithHTML:(NSString*)HTML pathForPDF:(NSString*)PDFpath delegate:(id )delegate
pageSize:(CGSize)pageSize margins:(UIEdgeInsets)pageMargins;
Step 5: Now write one protocol HTMLtoPDFDelegate which extend the protocal to be of type “NSObject” In which we can declare the two methods HTMLtoPDFDidSucceed: and HTMLtoPDFDidFail: These protocol methods will returns the generated pdf file to HtmlToPdfDemoViewController. Following are the code for HTMLtoPDF.h file.
// Declare pdf paper size #define kPaperSizeA4 CGSizeMake(595,842) #define kPaperSizeLetter CGSizeMake(612,792) @protocol NDHTMLtoPDFDelegate @optional - (void)HTMLtoPDFDidSucceed:(NDHTMLtoPDF*)htmlToPDF; - (void)HTMLtoPDFDidFail:(NDHTMLtoPDF*)htmlToPDF; @end @interface NDHTMLtoPDF : UIViewController @property (nonatomic, weak) id delegate; @property (nonatomic, strong, readonly) NSString *PDFpath; + (id)createPDFWithHTML:(NSString*)HTML pathForPDF:(NSString*)PDFpath delegate:(id )delegate pageSize:(CGSize)pageSize margins:(UIEdgeInsets)pageMargins; @end
To convert html to pdf look at the HTMLtoPDF.m
#import "NDHTMLtoPDF.h"
@interface UIPrintPageRenderer (PDF)
- (NSData*) printToPDF;
@end
@implementation NDHTMLtoPDF
- (void)viewDidLoad
{
[super viewDidLoad];
self.webview = [[UIWebView alloc] initWithFrame:self.view.frame];
webview.delegate = self;
[self.view addSubview:webview];
[webview loadHTMLString:self.HTML baseURL:nil];
}
+ (id)createPDFWithHTML:(NSString*)HTML pathForPDF:(NSString*)PDFpath delegate:(id )delegate
pageSize:(CGSize)pageSize margins:(UIEdgeInsets)pageMargins
{
NDHTMLtoPDF *creator = [[NDHTMLtoPDF alloc] initWithHTML:HTML delegate:delegate pathForPDF:PDFpath pageSize:pageSize margins:pageMargins];
return creator;
}
- (id)initWithHTML:(NSString*)HTML delegate:(id )delegate
pathForPDF:(NSString*)PDFpath pageSize:(CGSize)pageSize margins:(UIEdgeInsets)pageMargins
{
self = [super init];
if (self)
{
self.HTML = HTML;
self.delegate = delegate;
self.PDFpath = PDFpath;
self.pageMargins = pageMargins;
self.pageSize = pageSize;
[[UIApplication sharedApplication].delegate.window addSubview:self.view];
self.view.frame = CGRectMake(0, 0, 1, 1);
self.view.alpha = 0.0;
}
return self;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (webView.isLoading) return;
UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];
[render addPrintFormatter:webView.viewPrintFormatter startingAtPageAtIndex:0];
CGRect printableRect = CGRectMake(self.pageMargins.left,
self.pageMargins.top,
self.pageSize.width - self.pageMargins.left - self.pageMargins.right,
self.pageSize.height - self.pageMargins.top - self.pageMargins.bottom);
CGRect paperRect = CGRectMake(0, 0, self.pageSize.width, self.pageSize.height);
[render setValue:[NSValue valueWithCGRect:paperRect] forKey:@"paperRect"];
[render setValue:[NSValue valueWithCGRect:printableRect] forKey:@"printableRect"];
NSData *pdfData = [render printToPDF];
[pdfData writeToFile: self.PDFpath atomically: YES];
[self terminateWebTask];
if (self.delegate && [self.delegate respondsToSelector:@selector(HTMLtoPDFDidSucceed:)])
[self.delegate HTMLtoPDFDidSucceed:self];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
if (webView.isLoading) return;
[self terminateWebTask];
if (self.delegate && [self.delegate respondsToSelector:@selector(HTMLtoPDFDidFail:)])
[self.delegate HTMLtoPDFDidFail:self];
}
- (void)terminateWebTask
{
[self.webview stopLoading];
self.webview.delegate = nil;
[self.webview removeFromSuperview];
[self.view removeFromSuperview];
self.webview = nil;
}
@end
@implementation UIPrintPageRenderer (PDF)
- (NSData*) printToPDF
{
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData( pdfData, CGRectZero, nil );
[self prepareForDrawingPages: NSMakeRange(0, self.numberOfPages)];
CGRect bounds = UIGraphicsGetPDFContextBounds();
for ( int i = 0 ; i < self.numberOfPages ; i++ )
{
UIGraphicsBeginPDFPage();
[self drawPageAtIndex: i inRect: bounds];
}
UIGraphicsEndPDFContext();
return pdfData;
}
@end
Step 6: Move to the HtmlToPdfDemoViewController.m htmlToPdfButtonPressed: method. From that method we have to call createPDFWithHTML: method and pass html, path for storing the pdf file, page size and margins.
- (IBAction)htmlToPdfButtonPressed:(id)sender
{
NSString *html = [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.outerHTML"];
self.PDFCreator = [NDHTMLtoPDF createPDFWithHTML:html
pathForPDF:[@"~/Documents/demo.pdf" stringByExpandingTildeInPath]
delegate:self
pageSize:kPaperSizeLetter
margins:UIEdgeInsetsMake(10, 5, 10, 5)];
}
Step 7: In HtmlToPdfDemoViewController implements the HTMLtoPDFDelegate methods where you can get pdf file.
- (void)HTMLtoPDFDidSucceed:(NDHTMLtoPDF*)htmlToPDF
{
NSLog(@"HTMLtoPDF did succeed (%@ / %@)", htmlToPDF, htmlToPDF.PDFpath);
}
- (void)HTMLtoPDFDidFail:(NDHTMLtoPDF*)htmlToPDF
{
NSLog(@"HTMLtoPDF did fail (%@)", htmlToPDF);
}
Finally generated pdf (demo.pdf) saves into the documents directory. If you run the app on simulator you can find (demo.pdf) in Documents directory in our Library folder, inside iPhone Simulator.
