-(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
// Creates a mutable data object for updating with binary data, lik
Swift 2.0 solution, how to save pdf from webview to NSData:
func webViewDidFinishLoad(webView: UIWebView) {
let pdfData = createPdfFile(webView.viewPrintFormatter())
pdfData.writeToFile("/path/to/file", atomically: true)
}
func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSData {
let renderer = UIPrintPageRenderer()
renderer.addPrintFormatter(printFormatter, startingAtPageAtIndex: 0);
let paperSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)
let printableRect = CGRectMake(0, 0, paperSize.width, paperSize.height)
let paperRect = CGRectMake(0, 0, paperSize.width, paperSize.height);
renderer.setValue(NSValue(CGRect: paperRect), forKey: "paperRect")
renderer.setValue(NSValue(CGRect: printableRect), forKey: "printableRect")
return renderer.printToPDF()
}
You also need to add UIWebViewDelegate to your ViewController and extension for UIPrintPageRenderer.
extension UIPrintPageRenderer {
func printToPDF() -> NSData {
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil)
self.prepareForDrawingPages(NSMakeRange(0, self.numberOfPages()))
let bounds = UIGraphicsGetPDFContextBounds()
for i in 0..<self.numberOfPages() {
UIGraphicsBeginPDFPage();
self.drawPageAtIndex(i, inRect: bounds)
}
UIGraphicsEndPDFContext();
return pdfData;
}
}
UIWebView is deprecated now. Use WKWebView extension to create PDF from WKWebView
Credit: http://www.swiftdevcenter.com/create-pdf-from-uiview-wkwebview-and-uitableview/
Swift 4.2
extension WKWebView {
// Call this function when WKWebView finish loading
func exportAsPdfFromWebView() -> String {
let pdfData = createPdfFile(printFormatter: self.viewPrintFormatter())
return self.saveWebViewPdf(data: pdfData)
}
func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSMutableData {
let originalBounds = self.bounds
self.bounds = CGRect(x: originalBounds.origin.x,
y: bounds.origin.y,
width: self.bounds.size.width,
height: self.scrollView.contentSize.height)
let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width,
height: self.scrollView.contentSize.height)
let printPageRenderer = UIPrintPageRenderer()
printPageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
printPageRenderer.setValue(NSValue(cgRect: UIScreen.main.bounds), forKey: "paperRect")
printPageRenderer.setValue(NSValue(cgRect: pdfPageFrame), forKey: "printableRect")
self.bounds = originalBounds
return printPageRenderer.generatePdfData()
}
// Save pdf file in document directory
func saveWebViewPdf(data: NSMutableData) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("webViewPdf.pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
}
extension UIPrintPageRenderer {
func generatePdfData() -> NSMutableData {
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil)
self.prepare(forDrawingPages: NSMakeRange(0, self.numberOfPages))
let printRect = UIGraphicsGetPDFContextBounds()
for pdfPage in 0..<self.numberOfPages {
UIGraphicsBeginPDFPage()
self.drawPage(at: pdfPage, in: printRect)
}
UIGraphicsEndPDFContext();
return pdfData
}
}
It will save PDF file in the directory and returns pdf file path.
It looks like the issue may come from the hardcoded height 648. What happens if you change all the instances of 648 to calling the windows screenHeight?
//Grab the windows width and height.
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
Thank you for your answers Firemarble, it helped me a lot. I managed to get a somewhat good looking results with this method :
-(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];
}
Swift 3 solution of @Dan Loewenherz answer:
func webViewDidFinishLoad(_ webView: UIWebView) {
let pdfData = createPdfFile(printFormatter: webView.viewPrintFormatter())
pdfData.write(toFile: "/path/to/file", atomically: true)
}
func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSData {
let renderer = UIPrintPageRenderer()
renderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
let point = CGPoint(x:0,y:0)
let paperSize = CGSize(width: self.view.frame.size.width, height: self.view.frame.size.height)
let printableRect = CGRect(origin: point, size: CGSize(width:paperSize.width, height: paperSize.height))
let paperRect = CGRect(origin: point, size: CGSize(width: paperSize.width, height: paperSize.height))
renderer.setValue(NSValue(cgRect: paperRect), forKey: "paperRect")
renderer.setValue(NSValue(cgRect: printableRect), forKey: "printableRect")
return renderer.printToPDF()
}
extension UIPrintPageRenderer {
func printToPDF() -> NSData {
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil)
self.prepare(forDrawingPages: NSMakeRange(0, self.numberOfPages))
let bounds = UIGraphicsGetPDFContextBounds()
for i in 0..<self.numberOfPages {
UIGraphicsBeginPDFPage();
self.drawPage(at: i, in: bounds)
}
UIGraphicsEndPDFContext();
return pdfData;
}
}
Use UIPrintPageRenderer
from UIWebView
Follow below steps :
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
#define kPaperSizeA4 CGSizeMake(595.2,841.8)
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");
}
}