Monday 15 April 2013

Convert Html to pdf in iOS


 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.

No comments:

Post a Comment