Electron打印的四种方案

2021-08-19

述求

Electron是一个使用Web技术构建跨平台桌面应用的框架。现有一个基于Electron的桌面应用,想提供打印功能,点击界面上的按钮,跟电脑连接的打印机就能打印出指定的页面。

Electron打印

如上图所示,电脑通过USB线连接打印机,安装好了驱动,可以正常调起打印普通文件。我们的Electron应用中渲染了一个HTML网页,想把这个网页的内容打印出来。


方案一:window.print()

创建一个窗口,加载网页(链接或本地文件二选一即可):

const { BrowserWindow } = require('electron');
const win = new BrowserWindow();

// 链接
win.loadURL('https://blog.oonne.com');

// 本地文件
win.loadFile('index.html');

然后在加载的这个网页代码里,直接调用 window.print()  即可。


window.print()是浏览器中标准打印方法,所有桌面浏览器都能支持。在Chrome中调用,会弹出打印预览窗口,跟直接在页面上右键点打印的效果一致。在Electron中调用,会直接调起选择打印机的窗口。选好了打印机,点确定即可打印:网页打印

如果页面还没渲染完就调用这个方法,会等页面渲染完成再调起打印。打印前会触发beforeprint事件,打印后会触发afterprint事件,可以修改打印样式、做一些回调之类的。


这个方案不仅方便,而且能在浏览器里也是完全兼容的。但每次点打印,都会弹出选择打印机的弹框,体验还是不够好。


方案二:webview.print()

<webview>标签可以在一个独立的 frame 和进程里显示外部 web 内容,并提供print方法。

不过,由于架构调整的原因,Electron官方建议不使用 webview 标签,并在Electron >= 5以后开始禁用 webview
 标签。本方案也可以被下述方案完全替代,因此不建议使用。


方案三:webContents.print()

const { BrowserWindow } = require('electron');
const win = new BrowserWindow();
win.loadURL('https://blog.oonne.com');

// 获取webContent
const contents = win.webContents;
// 获取打印机列表
const printerList = contents.getPrinters();
// 打印
contents.print();

webContents 是 BrowserWindow 对象的一个属性,负责渲染和控制网页。我们首先使用其 getPrinters()方法(或异步的getPrintersAsync()),获取到系统的打印机列表,用户选择完打印机后记录下来。每次需要打印的时候,调用 print() 方法,入参silent设为true,deviceName设为之前选好的打印机名,即可打印出内容,并且不需要再弹出选择打印机的弹框。


方案四:网络打印

不要被条件限制了想象力。虽然题目说“一台装了驱动的电脑”,但并没有规定一定要用到这个驱动,对吧?

打印机最终接收到的,是打印控制指令,如ESC/POS指令。我们在电脑上安装的打印驱动,作用是将计算机要表达的内容,“翻译”成ESC/POS指令,再发打印机。很多打印机提供网络接功能,可以通过网线接入打印机,使用RAW协议直接发送指令给打印机。对于没有提供网络接口的打印机,也可以利用带有这个功能的路由器作为中转:

网络打印

通过网络连接上打印机之后,打印机暴露给电脑的是一个ip地址和端口。只要往这个端口发指令,就能把内容给打印出来。


此方案的优点:


缺点:


这个方案的网络打印原理,可以参考我写的《网络打印协议入门》。另外,近年来很多厂商也提供云打印方案,可以参考我另一篇文章《云打印原理入门》。


总结

本文介绍了基于Electron实现打印的若干方案。

想要一套代码同时跑在浏览器和Electron中,建议选择方案一。

想要体验好,每次打印不用弹出选择打印机窗口,建议选择方案三。

对打印机原理有较深入了解,且有更复杂的打印的需求,可以尝试一下方案四。

至于怎么渲染样式,界面和渲染进程怎么通信,此处就不展开讲了。有需要可以参考我在Github上写的Demo,使用React来渲染打印样式,ipcRenderer负责主进程和打印进程之间的通信,webContents.print()调起打印。



本文未经许可禁止转载,如需转载关注微信公众号【工程师加一】并留言。