Saving WebView to PDF returns blank image?

I'm trying to figure out how to save WebView to PDF and get completely stuck, will you really like it?

I do this in Cocoa and Swift on OSX, here is my code:

import Cocoa import WebKit class ViewController: NSViewController { override func loadView() { super.loadView() } override func viewDidLoad() { super.viewDidLoad() loadHTMLString() } func loadHTMLString() { let webView = WKWebView(frame: self.view.frame) webView.loadHTMLString("<html><body><p>Hello, World!</p></body></html>", baseURL: nil) self.view.addSubview(webView) createPDFFromView(webView, saveToDocumentWithFileName: "test.pdf") } func createPDFFromView(view: NSView, saveToDocumentWithFileName fileName: String) { let pdfData = view.dataWithPDFInsideRect(view.bounds) if let documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first { let documentsFileName = documentDirectories + "/" + fileName debugPrint(documentsFileName) pdfData.writeToFile(documentsFileName, atomically: false) } } } 

This is pretty simple what I do by creating a WebView and writing some basic html content into it that does this:

View

And then it takes the view and saves it in a PDF file, but it looks empty:

Pdf

I tried to grab content from webView and View, but without joy.

I found a similar problem here How to take a screenshot when the web view has finished solving regarding saving the web view to the image, but still no luck with OSX Solution.

Maybe this is due to the size of the document? or what is the content in sub? maybe if you capture a View you cannot capture a SubView?

Any ideas?

+6
source share
2 answers

iOS 11.0 and above , Apple has provided the following API for capturing a WKWebView snapshot.

 @available(iOS 11.0, *) open func takeSnapshot(with snapshotConfiguration: WKSnapshotConfiguration?, completionHandler: @escaping (UIImage?, Error?) -> Swift.Void) 

Sample Usage:

 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { if #available(iOS 11.0, *) { webView.takeSnapshot(with: nil) { (image, error) in //Do your stuff with image } } } 

iOS 10 and below , UIWebView should be used to capture a snapshot. To achieve this, you can use the following method.

 func webViewDidFinishLoad(_ webView: UIWebView) { let image = captureScreen(webView: webView) //Do your stuff with image } func captureScreen(webView: UIWebView) -> UIImage { UIGraphicsBeginImageContext(webView.bounds.size) webView.layer.render(in: UIGraphicsGetCurrentContext()!) let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return image } 

Here is another important answer

+1
source

So, I somehow figured out how to solve it, it turns out you cannot (especially on OSX) access and print the web view from WKWebView.

You should use WebView and NOT WKWebView (I originally started with WKWebView, because some of the articles I read said they use this).

The WebView object is pretty much like the WKWebView object, which is fun as hell :-)

But it gives you access to the .mainFrame and .frameView, which you will need to print.

Here is my code:

  let webView = WebView(frame: self.view.frame) let localfilePath = NSBundle.mainBundle().URLForResource(fileName, withExtension: "html"); let req = NSURLRequest(URL: localfilePath!); webView.mainFrame.loadRequest(req) self.view.addSubview(webView) 

After rendering, I added a 1 second delay to make sure the content was displayed before I print it,

  // needs 1 second delay let delay = 1 * Double(NSEC_PER_SEC) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay)) dispatch_after(time, dispatch_get_main_queue()) { // works! let data = webView.dataWithPDFInsideRect(webView.frame) let doc = PDFDocument.init(data: data) doc.writeToFile("/Users/john/Desktop/test.pdf") // works! let printInfo = NSPrintInfo.sharedPrintInfo() let printOperation = NSPrintOperation(view: webView.mainFrame.frameView, printInfo: printInfo) printOperation.runOperation() } 

Here I print it and save it as a PDF, so I'm sure it works under any circumstances.

I am sure that it can be improved, I hate hacking delays, I have to replace it with some kind of callback or delegate to run when the content is fully loaded.

+1
source

All Articles