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.