Objective-C Problems with UIWebView in PDF

I have this method here that takes my UIWebView and converts to PDF and it works well. But when I print this PDF file or send it by email, it turns off. This is similar to the size of the UIWebView that I set (width: 688 and height: 577). If I increase the size of the UIWebView to 300 or 1024, my PDF file will be empty. My UIWebView is over 577, but in my application I can scroll.

Here is the method ....

-(void)webViewDidFinishLoad:(UIWebView *)webViewPDF { CGRect origframe = webViewPDF.frame; NSString *heightStr = [webViewPDF stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"]; // Get the height of our webView int height = [heightStr intValue]; CGFloat maxHeight = kDefaultPageHeight - 2*kMargin; int pages = floor(height / maxHeight); NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; self.pdfPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"Purchase Order.pdf"]]; UIGraphicsBeginPDFContextToFile(self.pdfPath, CGRectZero, nil); for (int i = 0; i < pages; i++) { if (maxHeight * (i+1) > height) { CGRect f = [webViewPDF frame]; f.size.height -= (((i+1) * maxHeight) - height); [webViewPDF setFrame: f]; } UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil); CGContextRef currentContext = UIGraphicsGetCurrentContext(); CGContextTranslateCTM(currentContext, kMargin, kMargin); [webViewPDF.layer renderInContext:currentContext]; } UIGraphicsEndPDFContext(); [webViewPDF setFrame:origframe]; [[[webViewPDF subviews] lastObject] setContentOffset:CGPointMake(0, 0) animated:NO]; } 

Hope this makes sense ... Does anyone have any suggestions for fixing this, so the PDF is not cropped?

I forgot to mention these variables:

 #define kDefaultPageHeight 850 #define kDefaultPageWidth 850 #define kMargin 50 

Here is my button:

 - (IBAction)Share:(id)sender { NSData *pdfData = [NSData dataWithContentsOfFile:self.pdfPath]; UIActivityViewController * activityController = [[UIActivityViewController alloc] initWithActivityItems:@[pdfData] applicationActivities:nil]; UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:activityController]; [popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width - 36, 60, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES]; } 
+6
source share
2 answers

I have done this in the past using UIPrintPageRenderer. This is a more realistic way to create a PDF file from UIWebView, and it has been working for me so far. I tested this solution with Xcode 6 and iOS 8.2. In addition, I tried to print the resulting PDF file and everything printed fine.

When I read the OP, I did some testing with different page sizes to find out if I could get an empty PDF file. There are several key elements that I have identified that can contribute to an empty PDF file. I identified them in the code.

When you call webViewDidFinishLoad (), the view may not load 100%. A check is needed to see if viewing continues. This is important as it may be the source of your problem. If this is not so, then we will be happy. It is very important to note here. Some web pages load dynamically (defined on the page itself). Take, for example, youtube.com. The page is displayed almost immediately, with a loading screen. This will trick our webview, and its isLoading property will be set to false, while the webpage is still loading content dynamically. However, this is a fairly rare case, and in general, this solution will work well. If you need to create a PDF file from such a dynamic download page, you may need to move the actual generation to another location. Even with a dynamic loading web page, you will get a PDF file showing the loading screen, and not an empty PDF file.

Another key aspect is setting printableRect and pageRect. Please note that they are installed separately. If the printableRect value is less than paperRect, you will get some addition to the content - see, For example, the code. Here is the link in the Apple APIs document with some brief descriptions for both.

The sample code below adds a category to the UIPrintPageRenderer to create the actual PDF data. The code in this example was compiled using various resources on the Internet in the past, and I could not find which ones were used for proper lending.

 @interface UIPrintPageRenderer (PDF) - (NSData*) createPDF; @end @implementation UIPrintPageRenderer (PDF) - (NSData*) createPDF { 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 

And here is what I have in webViewDidFinishLoad ()

 - (void)webViewDidFinishLoad:(UIWebView *)webViewIn { NSLog(@"web view did finish loading"); // webViewDidFinishLoad() could get called multiple times before // the page is 100% loaded. That why we check if the page is still loading if (webViewIn.isLoading) return; UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init]; [render addPrintFormatter:webViewIn.viewPrintFormatter startingAtPageAtIndex:0]; // Padding is desirable, but optional float padding = 10.0f; // Define the printableRect and paperRect // If the printableRect defines the printable area of the page CGRect paperRect = CGRectMake(0, 0, PDFSize.width, PDFSize.height); CGRect printableRect = CGRectMake(padding, padding, PDFSize.width-(padding * 2), PDFSize.height-(padding * 2)); [render setValue:[NSValue valueWithCGRect:paperRect] forKey:@"paperRect"]; [render setValue:[NSValue valueWithCGRect:printableRect] forKey:@"printableRect"]; // Call the printToPDF helper method that will do the actual PDF creation using values set above NSData *pdfData = [render createPDF]; // Save the PDF to a file, if creating one is successful if (pdfData) { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; NSString *pdfPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"Purchase Order.pdf"]]; [pdfData writeToFile:pdfPath atomically:YES]; } else { NSLog(@"error creating PDF"); } } 

PDFSize is defined as a constant defined by the standard A4 page size. It can be edited according to your needs.

 #define PDFSize CGSizeMake(595.2,841.8) 
+5
source

To create a PDF file in memory, you need to draw a layer of the UIWebBrowserView instance that is under the UIWebView scrollView . To do this, try changing your call to renderInContext: as follows:

 UIView* contentView = webViewPDF.scrollView.subviews.firstObject; [contentView.layer renderInContext:currentContext]; 

Also, if you are targeting iOS> = 7.0, you can avoid using renderInContext: and use one of snapshotViewAfterScreenUpdates: or drawViewHierarchyInRect:afterScreenUpdates:

+2
source

Source: https://habr.com/ru/post/987092/


All Articles