5

In my iOS application, I want to create a PDF from UIWebView/UIView (including subviews). In my app, I will first load the original incoming PDF in UIWebView, and then add an image as a subview on UIWebView. I want to create a PDF from the UIWebview with this image (subview) with original clarity and no data loss.

PS : Image in rendered PDF should be in the same place as in the UIWebView.

I am able to create a PDF from UIWebView, but it lacks the PDF clarity and creates a border issue.

Can anyone please provide a clear solution for PDF rendering from UIWebView (including subviews)?

EDITED CONTENT:

enter image description here

Above is the screenshot of UIWebView. Signature(test) is the image in the subview. I want to render this as a PDF with clarity and without any data loss.

In the below answers, UIPrintPageRenderer renders the PDF from UIWebView, but it ignores the subviews above UIWebView. This is the major issue with this option.

Another answer using the createPDFfromUIView method lacks the original clarity:

   -(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename;

A border issue also occurs with this method.

I have also tried to write on the PDF directly, without taking a screenshot, using the below code from this reference.

- (void) drawCustomPDFContent
{
    //  Put your drawing calls here
    //  Draw a red box
    [[UIColor redColor] set];
    UIRectFill(CGRectMake(20, 20, 100, 100));

    //  Example of drawing your view into PDF, note that this will be a rasterized bitmap, including the text.
    //  To get smoother text you'll need to use the NSString draw methods
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [view.layer renderInContext:ctx];
}

- (void) createCustomPDF
{
    NSURL* pdfURL = ... /* URL to pdf file */;
    CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);

    const size_t numberOfPages = CGPDFDocumentGetNumberOfPages(pdf);

    NSMutableData* data = [NSMutableData data];
    UIGraphicsBeginPDFContextToData(data, CGRectZero, nil);

    for(size_t page = 1; page <= numberOfPages; page++)
    {
        //  Get the current page and page frame
        CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdf, page);
        const CGRect pageFrame = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);

        UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);

        //  Draw the page (flipped)
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextSaveGState(ctx);
        CGContextScaleCTM(ctx, 1, -1);
        CGContextTranslateCTM(ctx, 0, -pageFrame.size.height);
        CGContextDrawPDFPage(ctx, pdfPage);
        CGContextRestoreGState(ctx);

        if(page == 1)
        {
            [self drawCustomPDFContent];
        }
    }

    UIGraphicsEndPDFContext();

    CGPDFDocumentRelease(pdf);
    pdf = nil;

    //  Do something with data here
    [data writeToFile:... atomically:YES];
}

It does the job. However, (x,y) coordinates in UIWebView differ from the original PDF coordinates, so I can't map the exact coordinates to draw on the PDF to render.

Hopefully, this clears up my issue. Please suggest a way to resolve my issue. If it is likely impossible, please suggest the iOS PDF kit/SDK that meets my requirement.

Community
  • 1
  • 1
santhosh
  • 1,191
  • 4
  • 14
  • 28

2 Answers2

2

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");
  }
}
Paresh Navadiya
  • 38,095
  • 11
  • 81
  • 132
0
-(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];
//  CGRect screenRect = [[UIScreen mainScreen] bounds];
//  CGFloat screenHeight = (self.contentWebView.hidden)?screenRect.size.width:screenRect.size.height;
CGFloat screenHeight = webView.bounds.size.height;
int pages = ceil(height / screenHeight);

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

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

    [[[webView subviews] lastObject] setContentOffset:CGPointMake(0, screenHeight * 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];
 }
Mohd Prophet
  • 1,511
  • 10
  • 17