背景
因为工作需要,经常会打印一些文件,比如pdf,但是量变引起质变,就算是简单的打印每次都要确认也会变得非常繁琐。
那么有没有简便的方法去打印文件呢?当然是有的,通常我们打印文件有两种途径。
(目前市面上打印机种类千奇百怪,但实际原理大同小异,建议阅读本文时注重原理,不要生搬硬套)
打印方法
调用打印机驱动程序打印
一般情况下程序的默认的打印均是通过OS系统自带的打印服务去打印机驱动程序实现打印。
前端浏览器一般只提供window.print()
这一基础API,且只可打印当前页面,无法打印任意文件,仅少数格式文件支持在使用浏览器打开后单独打印(如pdf文件)
如果我们想要用油猴脚本去实现任意文件打印,可以参考
[油猴脚本开发指南]前后端相结合实现静默下载
https://bbs.tampermonkey.net.cn/thread-4944-1-1.html
将文件转发至后端服务器(如Node.js、Python等),然后让后端调用系统打印服务实现打印。
这种方法本文不再赘述,主要着重第二种方法。
调用打印机远程打印接口
(并非所有打印机都有远程打印功能,建议先参考打印机使用手册)
(且有些打印机远程打印只提供了exe程序,没有前端页面,这就需要通过额外工具进行抓包)
本文以Fuji Xerox ApeosPort 4570为例,该型号打印机远程打印提供了一个本地网页UI。
通常情况下我们需要远程打印时可以在这个UI中上传文件,进行设定,再一次一次打印。
我们可以打开控制台后先使用这个UI打印一次,然后观察控制台会发现刚才提交了一次请求,查看请求内容。
可以发现,我们通过ajax发送了一个POST请求到打印机远程接口,并将文件二进制内容以及打印设置存放在FormData中作为POST数据发送了出去。
并没有其他什么特殊内容,那么就非常简单了,我们直接将这个ajax请求转化为GMxhr请求,这就使得我们可以在油猴中实现任意打印这一需求。
参考代码(注重原理)
const pdf = await new Promise((resolve) =>
GM_xmlhttpRequest({
// 从指定url下载文件
// 文件格式需要是打印机支持打印的格式 否则需要提前转换
// 如果是本地url,需要在浏览器插件设置中允许脚本管理器访问本地url
url: 'file://D:/test.pdf',
responseType: 'blob', // 以Blob形式接收文件 二进制方便直接转换为打印机接口需要的File
onload: (xhr) => {
console.log(xhr);
resolve(xhr.response); // 二进制Blob
},
})
);
const file = new File([pdf], 'a.pdf'); // 将Blob转为File
const config = {
PrintMode: 'NORMAL',
UserName: '',
StartTime: '',
EncryptKey: '',
PrintQuantity: '1',
PaperSize: 'UNKNOWN',
PaperType: 'UNSPECIFIED',
PaperInTray: 'AUTO',
TwoSidedPrinting: 'ONESIDED',
CollateMode: 'UNSPECIFIED',
OutputDestination: '0_CENTER_UPPER',
File: file, // 二进制pdf文件内容
};
const formData = new FormData();
Object.keys(config).forEach((key) => {
formData.append(key, config[key]); // 将设置及文件构造为FormData
});
GM_xmlhttpRequest({
url: 'http://192.168.1.243/home/api/uploadfile-print?methodName=POST', // 打印机远程打印接口
method: 'POST',
data: formData, // FormData不要设置Content-Type,浏览器会读取boundary并自动设置,手动设置会覆盖自动设置,导致FormData无法被正常读取
responseType: 'json',
onload: (xhr) => {
console.log(xhr);
console.log(xhr.response);
},
});
参考结果
至此已实现了静默打印,如需批量打印,只需将函数封装,循环调用即可,这里不在赘述,就当一个小小的课后作业,自己实现吧。
完结撒花~
工作效率又提升了呢~😘