Search code examples
iosobjective-cpdfuiwebview

Creating PDF file from UIWebView


 -(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
    // Creates a mutable data object for updating with binary data, like a byte array
  UIWebView *webView = (UIWebView*)aView;
    NSString *heightStr = [webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"];

    int height = [heightStr intValue];

    // Get the number of pages needed to print. 9 * 72 = 648
    int pages = ceil(height / 648.0);

    NSMutableData *pdfData = [NSMutableData data];
    UIGraphicsBeginPDFContextToData( pdfData, CGRectZero, nil );
  CGRect frame = [webView frame];
    for (int i = 0; i < pages; i++) {
      // Check to see if page draws more than the height of the UIWebView
        if ((i+1) * 648 > height) {
            CGRect f = [webView frame];
            f.size.height -= (((i+1) * 648.0) - height);
            [webView setFrame: f];
        }

        UIGraphicsBeginPDFPage();
        CGContextRef currentContext = UIGraphicsGetCurrentContext();
        CGContextTranslateCTM(currentContext, 72, 72); // Translate for 1" margins

        [[[webView subviews] lastObject] setContentOffset:CGPointMake(0, 648 * i) animated:NO];
        [webView.layer renderInContext:currentContext];
    }

    UIGraphicsEndPDFContext();
    // Retrieves the document directories from the iOS device
  NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);

  NSString* documentDirectory = [documentDirectories objectAtIndex:0];
  NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename];

    // instructs the mutable data object to write its context to a file on disk
  [pdfData writeToFile:documentDirectoryFilename atomically:YES];
  [webView setFrame:frame];
  NSLog(@"documentDirectoryFileName: %@",documentDirectoryFilename);
}

I'm using the code above to generate a pdf file from a webview. It's working, however, the content is not cropped correctly : the content on the bottom of the pages get messed up. I think I could do something better using Core Graphics methods but I can't find how to do that. Any ideas ?


Solution

  • Use UIPrintPageRenderer from UIWebView Follow below steps :

    Add Category of UIPrintPageRenderer for getting PDF Data

    @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
    

    Add these define for A4 size

    #define kPaperSizeA4 CGSizeMake(595.2,841.8)
    

    Now in UIWebView's webViewDidFinishLoad delegate use UIPrintPageRenderer property of UIWebView.

    - (void)webViewDidFinishLoad:(UIWebView *)awebView
    {
      if (awebView.isLoading)
        return;
    
      UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];
      [render addPrintFormatter:awebView.viewPrintFormatter startingAtPageAtIndex:0];
      //increase these values according to your requirement
      float topPadding = 10.0f;
      float bottomPadding = 10.0f;
      float leftPadding = 10.0f;
      float rightPadding = 10.0f;
      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"];
      NSData *pdfData = [render printToPDF];
      if (pdfData) {
        [pdfData writeToFile:[NSString stringWithFormat:@"%@/tmp.pdf",NSTemporaryDirectory()] atomically: YES];
      }
      else
      {
        NSLog(@"PDF couldnot be created");
      }
    }