Creating PDF file from UIWebView

后端 未结 6 1935
天命终不由人
天命终不由人 2020-11-29 19:10
 -(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
    // Creates a mutable data object for updating with binary data, lik         


        
相关标签:
6条回答
  • 2020-11-29 19:41

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:42

    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.

    0 讨论(0)
  • 2020-11-29 19:46

    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;
    
    0 讨论(0)
  • 2020-11-29 19:50

    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];
    }
    
    0 讨论(0)
  • 2020-11-29 19:56

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:57

    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");
      }
    }
    
    0 讨论(0)
提交回复
热议问题