Creating PDF File from Uiwebview

iOS create pdf from UIWebview content

There isn't a method that allows this directly via the SDK like there is on Mac however you may wish to take a look at BNHtmlPdfKit which allows you to save the contents of URLs, web views and also html strings as PDFs.

For example, as follows:

self.htmlPdfKit = [BNHtmlPdfKit saveUrlAsPdf:[NSURL URLWithString:@"http://itsbrent.net"] toFile:@"...itsbrent.pdf" pageSize:BNPageSizeA6 success:^(NSString *pdfFileName) {
NSLog(@"Done");
} failure:^(NSError *err) {
NSLog(@"Failure");
}];

It makes use of a custom UIPrintPageRenderer which overrides paperRect and printableRect thus causing the UIPrintFormatter to return a pageCount as well as render the document.

Creating PDF file from UIWebView

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");
}
}

Download PDF via UIWebView

-initWithContentsOfURL: method of NSData does a simple HTTP GET, but you needed to set some Authorization params that's why it fails.

To avoid downloading twice the data, you could use NSURLSession to download it, save it, and use the -loadData:MIMEType:textEncodingName:baseURL: of UIWebView to load it.

NSMutableURLRequest *mutableRequest = //Your Custom request with URL and Headers
[[[NSURLSession sharedSession] dataTaskWithRequest:mutableRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error)
{
if (data)
{
//SaveDataIntoDisk
dispatch_async(dispatch_get_main_queue(), ^(){
[_webView loadData:data MIMEType:@"application/pdf" textEncodingName:@"UTF-8" baseURL:nil];
});
}
}] resume];

Download PDF, saving to document directory and loading it in UIWebView

I didn't look through all of the code but the following two lines are a problem:

var filePath = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("my.pdf").absoluteString
var targetURL = URL(fileURLWithPath: filePath)

The value of URL absoluteString does not give you a file path so the value of filePath is not a valid value for the URL fileURLWithPath: initializer.

And what's the point of going from URL to String (as a path) and back to a URL? Simply combine those two lines into:

var targetURL = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("my.pdf")

As a side note, use some consistency. In other code you get the Documents folder URL using:

let docURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last)

and in other code you use:

var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
var documentsDirectory = paths[0]
var ... = URL(fileURLWithPath: documentsDirectory)...

Pick one approach and use it consistently. Since you need a URL, use the first approach. This means the code I suggested should now be:

let docURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!
let targetURL = docURL.appendingPathComponent("my.pdf")

ios - create and load pdf in webview


UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0,0,screenSize.width,screenSize.height)];

I don't see anywhere where you actually add the UIWebView as a subView.

[self.view addSubview:webView];

Also. you should add the UIWebView to a property instead of allocating/creating it everytime someone presses a button.

@property (strong, nonatomic) UIWebView *webView;

Finally:

You should use a WKWebView instead of an UIWebView as mentioned in Apple Documentations:

Starting in iOS 8.0 and OS X 10.10, use WKWebView to add web content
to your app. Do not use UIWebView or WebView.

EDIT:

For people reading this who actually runs in to the problem as the question actually implies check these other threads on the same question:

Load text+pdf file in uiwebview

iPhone : can we open pdf file using UIWebView?

how to load pdf file in UIWebview center

Display local pdf file in UIWebView in iphone

Loading Local PDF File Into WebView

Objective-C Issues with UIWebView to PDF

I've done this in the past using UIPrintPageRenderer. It's a more versetile way of creating a PDF from a UIWebView, and it's been working well for me so far. I've tested this solution with Xcode 6 and iOS 8.2. Also, tried printing the resulting PDF and everything printed out fine.

When I read the OP, I did some testing with various page sizes, to see if I can get a blank PDF. There are a few key items that I identified, that could contribute to a blank PDF file. I've identified them in the code.

When webViewDidFinishLoad() gets called, the view might not be 100% loaded. A check is necessary, to see if the view is still loading. This is important, as it might be the source of your problem. If it's not, then we are good to go. There is a very important note here. Some web pages are loaded dynamically (defined in the page itself). Take youtube.com for example. The page displays almost immediately, with a "loading" screen. This will trick our web view, and it's "isLoading" property will be set to "false", while the web page is still loading content dynamically. This is a pretty rare case though, and in the general case this solution will work well. If you need to generate a PDF file from such a dynamic loading web page, you might need to move the actual generation to a different spot. Even with a dynamic loading web page, you will end up with a PDF showing the loading screen, and not an empty PDF file.

Another key aspect is setting the printableRect and pageRect. Note that those are set separately. If the printableRect is smaller than the paperRect, you will end up with some padding around the content - see code for example. Here is a link to Apple's API doc with some short descriptions for both.

The example code below adds a Category to UIPrintPageRenderer to create the actual PDF data. The code in this sample has been put together using various resources online in the past, and I wasn't able to find which ones were used to credit them properly.

@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's 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, set to a standard A4 page size. It can be edited to meet your needs.

#define PDFSize CGSizeMake(595.2,841.8)


Related Topics



Leave a reply



Submit