8

I am creating an iPad application, in that i have to use different PDF forms. I got some methods to generate PDF files through code using Quartz2D. But I have to write entire forms through code. I may have to update the PDF forms in future, so again I have to write the code. So I heard that there is a component called iTextSharp for .net pdf creation - is there something similar for iOS? So that I can use some XML templates to create the PDF files. Please help, thanks

Mithuzz
  • 1,091
  • 14
  • 43

2 Answers2

14

I do this in my app using the iOS print subsystem and the UIMarkupTextPrintFormatter. The trick is to write your own custom UIPrintPageRenderer that overrides and returns correct values from paperRect and numberOfPages. You'll add your UIMarkupTextPrintFormatter(s) to your custom UIPrintPageRenderer.

Then, you'll need routines similar to this, in the context of your custom UIPrintPageRenderer:

- (CGRect) paperRect
{
    if (!_generatingPdf)
        return [super paperRect];

    return UIGraphicsGetPDFContextBounds();
}

- (CGRect) printableRect
{
    if (!_generatingPdf)
        return [super printableRect];

    return CGRectInset( self.paperRect, 20, 20 );
}

- (NSData*) printToPDF
{
    _generatingPdf = YES;

    NSMutableData *pdfData = [NSMutableData data];

    UIGraphicsBeginPDFContextToData( pdfData, CGRectMake(0, 0, 792, 612), nil );  // letter-size, landscape

    [self prepareForDrawingPages: NSMakeRange(0, 1)];

    CGRect bounds = UIGraphicsGetPDFContextBounds();

    for ( int i = 0 ; i < self.numberOfPages ; i++ )
    {
        UIGraphicsBeginPDFPage();

        [self drawPageAtIndex: i inRect: bounds];
    }

    UIGraphicsEndPDFContext();

    _generatingPdf = NO;

//    NSString* filename = @"/Volumes/Macintosh HD 2/test.pdf";
//    [pdfData writeToFile: filename  atomically: YES];

    return pdfData;
}
TomSwift
  • 39,369
  • 12
  • 121
  • 149
  • are you generating the PDF files from an XML template? – Mithuzz Mar 06 '12 at 08:27
  • Thank you, you saved my life!By the way,is this method allowed by app store? – ChenXin Jun 08 '12 at 09:13
  • @ChenXin; I have an app approved using this technique. – TomSwift Jun 08 '12 at 15:43
  • Wow thanks a lot ! This is a great way to create PDF files, much better and easier than with core graphics. – nicolasthenoz Jul 18 '12 at 13:28
  • 3
    @TomSwift Did you manage to render images as well using this technique ? I tried several options (custom NSURLProtocol, local file URL, base64 image embedding) and nothing seems to work... Any help on that ? – nicolasthenoz Jul 20 '12 at 11:00
  • @nicholasthenoz. I haven't tried. Have you tried an image from your bundle, per this example?http://stackoverflow.com/questions/7058556/how-to-add-images-in-uimarkuptextprintformatter – TomSwift Jul 22 '12 at 23:57
  • @TomSwift Yeah I tried that and it actually works if you print the document using UIPrintInteractionController. But if you use your code to print, no image is ever rendered... I also tried defining a custom url protocol (http://stackoverflow.com/questions/5572258/ios-webview-remote-html-with-local-image-files), but same issue, as well as direct embedding of the images in base64 encoding... I really can't get my head around this... The UIPrintInteractionController must call some hidden method I don't see – nicolasthenoz Jul 23 '12 at 10:04
  • @nicolasthenoz did you end up figuring it out? – Jack Lawrence Sep 10 '12 at 00:40
  • Is this solution still functional? My subclassed page renderer never receives calls for printableRect or paperRect and I end up with blank PDF pages. – greg Sep 10 '12 at 20:09
  • @JackLawrence Well I did not succeed using a UIMarkupTextPrintFormatter so I tweaked it a little bit. I added a webview to my custom UIPrintPageRenderer, created a function which takes the html as a parameter and calls [UIWebView loadHTMLString:baseURL:]. Once the webview has finished loading, I add its viewPrintFormatter to the renderer and call printToPDF. Not the best method but it works, but you have to call it on the main thread as it is using a UI element. – nicolasthenoz Sep 18 '12 at 16:36
  • @nicolasthenoz Oooh interesting. `-[UIWebView viewPrintFormatter]` always returns 0 for `pageCount`, so by combining the method above with `viewPrintFormatter` you were able to provide a page count etc and still use the built in formatter. I'll try it out. – Jack Lawrence Sep 18 '12 at 17:01
  • can someone give me the complete coding to convert html to pdf ? I need it very badly – Raj Oct 29 '12 at 11:08
  • hi I have got one requirement that i have to load one html file and that html file will have text fields, labels, check box buttons etc. I have to get the data whatever user will enter and then i have to convert it into pdf with user enter data. – amit soni Apr 18 '13 at 19:56
  • @TomSwift I used this method.Everything is fine .But the text text is getting broken in between the pages.Is there any way to fix it. – UIBittu Oct 05 '16 at 12:47
1

@TomSwift : agree with his answer but i would like to explain in better way

To be able create PDF from UIWebView is load HTML to yourWebView or there might be case yourWebView can also be hidden to generate PDF but process remains the same

1) Added Category of UIPrintPageRenderer for getting PDF Data as yourWebView.viewPrintFormatter need to be used

@interface UIPrintPageRenderer (PDF)
- (NSData*) printToPDF;
@end

@implementation UIPrintPageRenderer (PDF)
- (NSData*) printToPDF
{
  NSMutableData *pdfData = [NSMutableData data];
  UIGraphicsBeginPDFContextToData( pdfData, self.paperRect, 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

2) Add these define for A4 size or any custom size you want

#define kPaperSizeA4 CGSizeMake(595.2,841.8)

3) Process how we can create PDF

//create print renderer
UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];
[render addPrintFormatter:yourWebView.viewPrintFormatter startingAtPageAtIndex:0];

//provide padding ---- increase these values according to your requirement
float topPadding = 10.0f;
float bottomPadding = 10.0f;
float leftPadding = 10.0f;
float rightPadding = 10.0f;

//provide rect for printing and for actual PDF Rect of page
CGRect printableRect = CGRectMake(leftPadding,
                                  topPadding,
                                  kPaperSizeA4.width-leftPadding-rightPadding,
                                  kPaperSizeA4.height-topPadding-bottomPadding);
CGRect paperRect = CGRectMake(0, 0, kPaperSizeA4.width, kPaperSizeA4.height);
[render setValue:[NSValue valueWithCGRect:paperRect] forKey:@"paperRect"];
[render setValue:[NSValue valueWithCGRect:printableRect] forKey:@"printableRect"];

//category created above is used here 
NSData *pdfData = [render printToPDF];
//Save PDF to directory for usage
if (pdfData) {
  [pdfData writeToFile:[NSString stringWithFormat:@"%@/tmp.pdf",NSTemporaryDirectory()] atomically: YES];
}
else
{
  NSLog(@"PDF couldnot be created");
}
Community
  • 1
  • 1
Paresh Navadiya
  • 38,095
  • 11
  • 81
  • 132