I have a Mac app that includes the ability to print some HTML. That part works fine and I get the print dialog popup and can print the output. However, the output needs have headers and footers added (a title and page numbers), but I'm hitting a brick wall with how to do this.
My existing print code looks like this:
public class HTMLPrintView: NSView {
var webView: WKWebView
public override init(frame frameRect: NSRect) {
webView = WKWebView(frame: frameRect)
super.init(frame: frameRect)
addSubview(webView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func printView(htmlContent: String, window parentWindow: NSWindow) {
let webView = WKWebView(frame: .zero)
webView.loadHTMLString(htmlContent, baseURL: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
let printInfo = NSPrintInfo()
printInfo.horizontalPagination = .fit
printInfo.verticalPagination = .fit
printInfo.topMargin = 40
printInfo.bottomMargin = 60
printInfo.leftMargin = 40
printInfo.rightMargin = 40
printInfo.isVerticallyCentered = true
printInfo.isHorizontallyCentered = true
let printOperation = webView.printOperation(with: printInfo)
printOperation.printPanel.options.insert(.showsPaperSize)
printOperation.printPanel.options.insert(.showsOrientation)
printOperation.printPanel.options.insert(.showsPreview)
printOperation.view?.frame = NSRect(x: 0.0, y: 0.0, width: 300.0, height: 300.0)
printOperation.runModal(for: parentWindow, delegate: self, didRun: nil, contextInfo: nil)
}
}
}
I create an instance of the HTMLPrintView and call the printView function.
I have tried overriding drawPageBorder, but that doesn't seem to be called.
Sadly, I'm finding very little information on printing in Mac apps. This is a SwiftUI based app, with the printing being done in the view model.
Any suggestions as to how I get headers and footers?
Thanks
I have messed around with this and have found a workable, if not elegant, solution. The code is below. To make things easier, I have added a struct to provide the options to my print routine:
public struct PrintOptions {
var header: String
var footer: String
var htmlContent: String
}
The print class now subclasses WKWebView and overrides the drawBorder function:
public class HTMLPrintView: WKWebView {
var pop: NSPrintOperation?
var printOptions: PrintOptions?
public override func drawPageBorder(with borderSize: NSSize) {
super.drawPageBorder(with: borderSize)
guard let pop,
let printOptions
else { return }
// Drawing the header
let headerAttributes: [NSAttributedString.Key: Any] = [
.font: NSFont.systemFont(ofSize: 10),
.foregroundColor: NSColor.black
]
let headerString = NSAttributedString(string: printOptions.header, attributes: headerAttributes)
headerString.draw(at: NSPoint(x: 30, y: borderSize.height - 50))
// Drawing the footer
let footerAttributes: [NSAttributedString.Key: Any] = [
.font: NSFont.systemFont(ofSize: 10),
.foregroundColor: NSColor.black
]
let footerString = NSAttributedString(string: printOptions.footer,
attributes: footerAttributes)
footerString.draw(at: NSPoint(x: 30, y: 30))
let pageString = NSAttributedString(string: "Page \(pop.currentPage)",
attributes: footerAttributes)
pageString.draw(at: NSPoint(x: borderSize.width - 80, y: 30))
}
public func printView(printOptions: PrintOptions, window parentWindow: NSWindow) {
loadHTMLString(printOptions.htmlContent, baseURL: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
let printInfo = NSPrintInfo()
printInfo.horizontalPagination = .fit
printInfo.verticalPagination = .fit
printInfo.topMargin = 60
printInfo.bottomMargin = 60
printInfo.leftMargin = 40
printInfo.rightMargin = 40
printInfo.isVerticallyCentered = false
printInfo.isHorizontallyCentered = false
self.pop = self.printOperation(with: printInfo)
self.printOptions = printOptions
self.pop!.printPanel.options.insert(.showsPaperSize)
self.pop!.printPanel.options.insert(.showsOrientation)
self.pop!.printPanel.options.insert(.showsPreview)
self.pop!.view?.frame = NSRect(x: 0.0, y: 0.0, width: 300.0, height: 900.0)
self.pop!.runModal(
for: parentWindow,
delegate: self,
didRun: nil,
contextInfo: nil
)
}
}
}
When I print my HTML, it now displays the page content and adds the headers and footers I wanted. It's going to need some tidying up, but it's a functioning piece of code, so a good starting point.