1

How to print the content of a WKWebView using printOperation(with:)?

First try

let info = NSPrintInfo.shared
let operation = printOperation(with: info)
operation.run()

But I get a crash with the message:

[Printing] ERROR: The NSPrintOperation view's frame was not initialized properly before knowsPageRange: returned. (WKPrintingView)

But the view property on NSPrintOperation is read only.

Second try

if instead I try to run the operation modally and disable the print panel like this:

operation.showsPrintPanel = false

guard let window = webView.window else { return }

operation.runModal(for: window, delegate: nil, didRun: nil, contextInfo: nil)

I get an alert with the message:

To print this file, you must set up a printer.

And it is true, I haven't setup a printer, but what about printing (i.e. saving) to PDF?

vicegax
  • 4,709
  • 28
  • 37
  • You can't print without a printer, does printing to PDF work without a printer? Or do you want to save as PDF? How about installing a printer, for example a PDF-writer? What is the value of `info.paperSize`? – Willeke Nov 05 '21 at 08:36
  • Good point @Willeke, I mean saving to PDF. I've just updated the question to clarify that. I call it printing to PDF because that is the way the system handles it, and it is in the printing flow that you can save to PDF. I'm not sure what the value for `info.paperSize` is, but maybe it is for opening a new question? – vicegax Nov 05 '21 at 08:46
  • If `info.paperSize` is `NSZeroRect` then `knowsPageRange` has a problem, it calculates the number of pages. Setting `info.paperSize` will solve this. With "save as PDF" I meant Export as PDF like Safari does (`createPDF(configuration:completionHandler:)`). – Willeke Nov 05 '21 at 08:56
  • Thanks for the feedback @Willeke. `info.paperSize` seems not to be a problem on the attempts I made, seems like when using `webView.printOperation(with:)` these details get filled properly. `WKWebView` can also export as PDF, but in this case I wanted to do test the printing process itself. I don't have a printer, so my way of validating if it works or not is by saving to PDF instead. As mentioned in the question, one of the issues was a crash, unrelated to having a printer installed or not. – vicegax Nov 05 '21 at 09:06

2 Answers2

3

I realised you can modify the view's frame on NSPrintOperation. It has to be a CGRect/NSRect of at least 100x100, apparently it resizes itself afterwards, and the position doesn't matter at all, this is what worked for me at the end:

let info = NSPrintInfo.shared
let operation = webView.printOperation(with: info)
operation.view?.frame = webView.bounds

guard let window = webView.window else { return }

operation.runModal(for: window, delegate: nil, didRun: nil, contextInfo: nil)

vicegax
  • 4,709
  • 28
  • 37
0

Taking the accepted answer didn't work for me, but a small modification fixed this:

operation.view?.frame = NSRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0)
guard let window = view.window else { return }
operation.runModal(for: window, delegate: nil, didRun: nil, contextInfo: nil)

Where view.window is (in my case) the main window of the app - the WKWebView was only used to load the HTML for the PDF.

Todd
  • 1,770
  • 1
  • 17
  • 42