打印
本指南介绍如何使用打印(Printing)API。
概述
网页可以通过以下方式之一进行打印:
使用
window.print()JavaScript 函数。该函数可以在网页的 JavaScript 代码中调用。使用 Fuzio API 的
Frame.print()方法。该方法会请求打印指定的帧。如果你需要打印整个页面,应在主帧中调用print()方法。例如:JavaKotlinbrowser.mainFrame().ifPresent(Frame::print);browser.mainFrame?.print()
网页不会立即开始打印。系统会调用 PrintCallback 来决定浏览器应如何处理打印请求。默认情况下,所有打印请求都会被取消。
打印预览
要允许打印请求并显示打印预览(Print Preview) 对话框,请使用以下代码:
browser.set(PrintCallback.class, (params, tell) -> tell.showPrintPreview());
browser.register(PrintCallback { params, tell ->
tell.showPrintPreview()
})
在打印预览对话框中,你可以选择所需的打印选项:

配置设置
使用以下代码通知浏览器继续打印:
browser.set(PrintCallback.class, (params, tell) -> tell.print());
browser.register(PrintCallback { params, tell ->
tell.print()
})
之后,会触发 PrintHtmlCallback 或 PrintPdfCallback ,以便你配置打印设置。触发哪个回调取决于浏览器当前加载的内容类型:PrintHtmlCallback 用于 HTML 内容,PrintPdfCallback 用于 PDF 内容。
下面我们来看看如何使用这些回调。
第 1 步:选择打印机
首先,你需要选择要使用的打印机。打印机分为两类:PdfPrinter 与 SystemPrinter。PdfPrinter 相当于打印预览对话框中的 Save as PDF。SystemPrinter 类型表示系统中安装的打印机,可以是虚拟的或物理的。回调参数提供了可用打印机的列表。您可以检索 PdfPrinter、默认系统打印机,或从系统打印机中选择一个:
browser.set(PrintHtmlCallback.class, (params, tell) -> {
// PDF 打印机始终可用。
var pdfPrinter = params.printers().pdfPrinter();
// 默认打印机是可选的。
var defaultPrinter = params.printers()
.defaultPrinter()
.orElseThrow(() -> new IllegalStateException("The default printer is not found."));
// 按名称查找系统打印机。
var systemPrinter = params.printers()
.list()
.stream()
.filter(printer -> printer.deviceName().equals("Microsoft XPS Document Writer"))
.findFirst()
.orElseThrow(() -> new IllegalStateException("The printer is not found."));
});
browser.register(PrintHtmlCallback { params, tell ->
// PDF 打印机始终可用。
val pdfPrinter = params.printers.pdf
// 默认打印机是可选的。
val defaultPrinter = params.printers.default!!
// 按名称查找系统打印机。
val systemPrinter = params.printers.list()
.firstOrNull { it.deviceName() == "Microsoft XPS Document Writer" }
?: throw IllegalStateException("The printer is not found.")
})
第 2 步:配置设置
每个打印机都对应一个 PrintSettings 类型,用于定义当前上下文下该打印机可用的打印设置。每个打印机都包含一个 PrintJob,表示当前打印操作。打印设置会应用到某个打印作业上:
var printer = params.printers()
.defaultPrinter()
.orElseThrow(IllegalStateException::new);
var printJob = printer.printJob();
printJob.settings()
.header("<span style='font-size: 12px;'>Page header:</span>"
+ "<span class='title'></span>")
.footer("<span style='font-size: 12px;'>Page footer:</span>"
+ "<span class='pageNumber'></span>")
.paperSize(ISO_A4)
.colorModel(COLOR)
.enablePrintingBackgrounds()
.disablePrintingHeaderFooter()
.orientation(PORTRAIT)
.apply();
val printer = params.printers.default!!
val printJob = printer.job
printJob.settings()
.header(
"<span style='font-size: 12px;'>Page header:</span>"
+ "<span class='title'></span>"
)
.footer(
"<span style='font-size: 12px;'>Page footer:</span>"
+ "<span class='pageNumber'></span>"
)
.paperSize(ISO_A4)
.colorModel(COLOR)
.enablePrintingBackgrounds()
.disablePrintingHeaderFooter()
.orientation(PORTRAIT)
.apply()
调用 apply() 会应用已配置的设置,并重新生成打印预览文档,之后该文档会被发送到打印机进行打印。
设置应用后,实际需要打印的页数可能会发生变化。你可以监听 PageCountUpdated 事件来获取页数,并在需要时调整设置:
printJob.on(PageCountUpdated.class, params -> {
var pageCount = params.pageCount();
var pageRange = PageRange.of(1, pageCount);
printJob.settings().pageRanges(pageRange).apply();
});
printJob.subscribe<PageCountUpdated> { event ->
val pageCount = event.pageCount()
val pageRange = PageRange.of(1, pageCount)
printJob.settings().pageRanges(pageRange).apply()
}
在通知浏览器开始打印之前,你还可以订阅 PrintCompleted 事件,以便在打印完成时收到通知:
printJob.on(PrintCompleted.class, event -> {
if (event.isSuccess()) {
System.out.println("Printing is completed successfully.");
} else {
System.out.println("Printing has failed.");
}
});
printJob.subscribe<PrintCompleted> { event ->
if (event.isSuccess) {
println("Printing is completed successfully.")
} else {
println("Printing has failed.")
}
}
第 3 步:开始打印
现在可以开始打印了:
tell.proceed(printer);
tell.proceed(printer)
下面是完整代码片段:
browser.set(PrintHtmlCallback.class, (params, tell) -> {
var printer = params.printers()
.defaultPrinter()
.orElseThrow(IllegalStateException::new);
var printJob = printer.printJob();
printJob.settings()
.header("<span style='font-size: 12px;'>Page header:</span>"
+ "<span class='title'></span>")
.footer("<span style='font-size: 12px;'>Page footer:</span>"
+ "<span class='pageNumber'></span>")
.paperSize(ISO_A4)
.colorModel(COLOR)
.enablePrintingBackgrounds()
.disablePrintingHeaderFooter()
.orientation(PORTRAIT)
.apply();
printJob.on(PrintCompleted.class, event -> {
if (event.isSuccess()) {
System.out.println("Printing is completed successfully.");
} else {
System.out.println("Printing has failed.");
}
});
tell.proceed(printer);
});
browser.register(PrintHtmlCallback { params, tell ->
val printer = params.printers.default!!
val printJob = printer.job
printJob.settings()
.header("<span style='font-size: 12px;'>Page header:</span>"
+ "<span class='title'></span>")
.footer("<span style='font-size: 12px;'>Page footer:</span>"
+ "<span class='pageNumber'></span>")
.paperSize(ISO_A4)
.colorModel(COLOR)
.enablePrintingBackgrounds()
.disablePrintingHeaderFooter()
.orientation(PORTRAIT)
.apply()
printJob.subscribe<PrintCompleted> { event ->
if (event.isSuccess) {
println("Printing is completed successfully.")
} else {
println("Printing has failed.")
}
}
tell.proceed(printer)
})
使用 PdfPrinter 打印的流程完全相同,不同之处在于你必须指定目标 PDF 文件路径:
browser.set(PrintHtmlCallback.class, (params, tell) -> {
var printer = params.printers().pdfPrinter();
var printJob = printer.printJob();
printJob.settings()
.paperSize(ISO_A4)
.enablePrintingBackgrounds()
.pdfFilePath(Paths.get("<path-to-pdf-file>"))
.apply();
printJob.on(PrintCompleted.class, event -> {
if (event.isSuccess()) {
System.out.println("Printing is completed successfully.");
} else {
System.out.println("Printing has failed.");
}
});
tell.proceed(printer);
});
browser.register(PrintHtmlCallback { params, tell ->
val printer = params.printers.pdf
val printJob = printer.job
printJob.settings()
.paperSize(ISO_A4)
.enablePrintingBackgrounds()
.pdfFilePath(Path("<path-to-pdf-file>"))
.apply()
printJob.subscribe<PrintCompleted> { event ->
if (event.isSuccess) {
println("Printing is completed successfully.")
} else {
println("Printing has failed.")
}
}
tell.proceed(printer)
})
PrintPdfCallback 具有相同的接口,唯一的区别在于可应用到打印作业上的打印设置项不同。
取消打印
要取消打印,请使用以下方式:
browser.set(PrintCallback.class, (params, tell) -> tell.cancel());
browser.register(PrintCallback { params, tell ->
tell.cancel()
})

