page2pdf_server
v2.1.0
Published
文书打印转换器的引用类型
Maintainers
Readme
Overview
page2pdf_server 文书打印转换器的引用类型定义; "repository": "https://gitee.com/heerzhang/page2pdf-server", Nothing new under the sun, just a straight forward combo to make server development a little bit faster. And of course, this make my freelancing days more enjoyable 😎 Comes with:
Everything typed with Typescript
ES6 features/modules
Run with Nodemon for automatic reload & watch
ESLint for code linting
Code formatting using Prettier
Configuration management using dotenv
Improved commits with Husky
Manage production app proccess with PM2
由来
目前动态生成的网页html在浏览器上直接打印时,不能支持纸张的横向或纵向方向的混合一次性的打印输出,当前做法只能拆开为多个的打印命令分别打印后再合并装订。 浏览器不同版本打印网页的效果稍有一点点差距就会导致文书打印时的页码目录针对的页号出现预先设想的页号和实际打印结果不一致性,这对于有些要求苛刻的文书打印, 动态网页直接打印明显处于不适应地位。为了缝合这个缺陷,特别地推出本软件功能。 原本猜想wkhtmltopdf可以,但是发现wkhtmltopdf对于动态生成的网页有js css的普通APP页面生成的效果不如谷歌浏览器好,常用的html2canvas+jsPDF, html2pdf.js方案以及更为原始的PDFKit方案都无法完美解决和浏览器的打印预览效果差异大的问题。chrome-remote-interface是比Puppeteer的API更底层的库。 chrome-remote-interface不会为您启动Chrome。本来想用chrome-remote-interface在纯粹的浏览器客户机环境下实现,但发现可能权限的理由导致尝试失败, 认定它和puppeteer一样都只能在node.js环境下有效,chrome-remote-interface比起puppeteer更为底层的。 本软件定名“文书打印转换器” page2pdf_server,本质是个node.js的web服务器,但实际只提供给本机使用,也不支持多个用户一起用的,web客户端也就是其它通用的 前端APP浏览器客户使用http url访问本服务模块,最终在本地主机目录生成pdf文件以供进一步打印或发送邮件或移走pdf文件。可支持SPA APP动态生成的网页多个链接 的合并输出,但前提要求这些网页URL在打印信号前必须安静下来亦即准备好视图,后续不会再执行脚本语言修改页面了。封面cover和目录TOC这些也需要应用层APP自己负责 去生成和校订页码的,不支持pdf的内部点击链接跳转显示页的能力,目标是直接给打印机打印使用的过渡性质的pdf,若要此类能力请直接回到APP动态网页的前端浏览去。 后续的真实打印机输出,请找ipp实现连接打印机后端静默打印html文件,pdf放入前端预览看react-file-preview-latest嵌入文档阅读器。 注意,动态网页在Chrome浏览器直接打印预览的效果应该和本软件转换输出的pdf一致效果,为打印设置的css必须在应用层中自己去添加的。 纯粹静态html的打印转换pdf,且是标准纸张大小的横竖纸张方向掺杂的这种情况:考虑一次提取一部分pageRanges[]吗,分解多个的files[url,out]独立生成之后做合并。
Prerequisites 必须配置的
- Node.js (
>= 20.0.0) - Yarn or NPM
- 客户电脑必须有Chrome浏览器;
- 之后服务期间,需要首先就该点击该链接开启Chrome浏览器。
- 特别注意:windows用户若非管理员账户的:桌面上的Chrome快捷方式右键点属性在“兼容性”设置中:必须勾选“管理员身份运行”; 注意浏览器的管理员和普通身份运行的效果进入显示都不同的。目标URL网站需要登陆处理的,登陆点击后浏览器没有反馈,需直接关闭该TAB页面。
Install
- Fork or Use this template repository.
- Clone the forked repository.
- Install the dependencies with yarn or npm.
Make sure you already have
node.jsandnpmoryarninstalled in your system.
- Set your
git remote add originpath - 用户电脑也需要做些安装的: 只需要本工程目录的 /config, /dist, 文书打印转换器.bat,新/pdfs目录, 并且页已经node.js, nodemon; 还必须要安装工程目录 package-lock.json; /module-alias/的目录全部依赖包的。
git remote add origin ${forked-and-cloned-path}Update the url if you already have an
origin
Config
具体API用法, 参考见../server 也即page2pdf_server_run服务器的包。
- Copy
.env.examplea file at the root of the application. - Add or modify specific variables and update it according to your need.
cp .env.example .envCheck the
configfolder to customize your settings (/src/config)
Alias 其它,对比 @
Puppeteer 是一个基于Chrome调试协议CDP 构建的额外高层 API,除其他功能外,它可以启动并使用捆绑版本的 Chromium,而非系统上安装的版本。 我这个工具目前使用CDP协议构建的,而不是利用Puppeteer做的。
To make paths clean and ease to access @ is setup up for /src path
// BEFORE
import config from './config';
import routes from './routes';
// NOW
import config from '@/config';
import routes from '@/routes';You can customize this setup:
/tsconfig.json> compilerOptions.paths/eslintrc.yml> rules.settings.alias.map
Local Development
Run the server locally. It will be run with Nodemon and ready to serve on port 8080 (unless you specify it on your .env)
yarn start # or npm startCheck
package.jsonto see more "scripts"
Production
First, build the application.
yarn build # or npm run buildThen, use pm2 to start the application as a service.
yarn service:start # or npm run service:startContribution
This repository will be managed as an open-source.
Please feel free to open an issue or a pull request to suggest changes or additions.
Support & Contact
If you have any question or suggestion, don't hesitate to contact me:
Author & Credits
windows驻守长期运行本服务,纯粹服务端模式
node.js必须有安装。执行底下命令: npm install pm2 -g npm install pm2-windows-startup -g 若运行 pm2-startup install 报错的 在系统中搜索Windows PowerShell,用管理员身份打开 打开窗口输入命令行 set-ExecutionPolicy RemoteSigned 输入y回车确认,再回头运行pm2-startup install。 pm2 start D:\home\page2pdf-server\dist\src\index.js --name page2pdf-server pm2 save #保证重启电脑可以自动跑 pm2 ls #查看守护服务情况,自带进程node C:\Users\herzhang\AppData\Roaming\npm\node_modules\pm2\lib\Daemon.js pm2 stop all # 停止所有服务进程 pm2 delete 0 # 删除服务(pm2 delete app_id) 要卸载服务,执行:pm2-service-uninstall 直接杀掉自带进程node; pm2 logs — 从所有正在运行的应用中输出日志 pm2 logs page2pdf-server — 只从指定的应用中输出日志 pm2 flush — 刷新所有日志数据,释放磁盘空间
前台可看得见输出的运行模式,windows环境的
npm install -g nodemon start nodemon D:\home\page2pdf-server\dist\src\index.js 桌面上整个 文书打印转换器.bat 双击运行。 文书打印转换器.bat 命令cmd窗口可能挂起,注意回撤继续。 cmd命令行窗口鼠标点击后挂起的原因和处理方法;https://blog.csdn.net/fanstering/article/details/116455669 注意Chrome浏览器启动cmd配置,chrome.exe --headless不能加,不然报错: No inspectable targets。
前端对接和使用API
http://localhost:9389/api/pdf 前端发送请求后,可观察浏览器页面以及本地工作目录生成文件和本文书打印转换器的终端输出,前端APP最好发起打印转换指令以后等待结果完成, 当然也允许不等待的,直接从转换器来获得结果输出,前端继续干别的事,但是应该保证本转换器只会单用户单进程排他的运作,不要同时进行多个转换命令。 要测试,用IDEA的HTTP客户端发送如下: POST http://localhost:9389/api/pdf Content-Type: application/json
{ "merge": true, "name": "asjsak啊实打实", "lay": { "head": "address" }, "files": [ { "url": "ChromePage7.pdf", "out": "add_ChromePag" }, { "url": "https://www.npmjs.com/search?q=chrome-remote-interface", "out": "横页脚的qa" } ] }
注意,如果发送post请求的body底下的内容实际为空的话,本转换器默认执行:把工作目录的所有pdf文件按照修改时间顺序进行合并,默认输出文件名=配置好的名字。 假若某个URL不正常的,很可能无法触发页面加载完成,导致作业一致无法继续下去,大大超出预期执行时间。URL对应网页若不是一次性加载完成还会陆陆续续修改内容的就是这种情况造成死等长时间没结果。
调试 "start": "NODE_ENV=development run-s prettify lint & nodemon" 用Debug,异步执行,打断块点有点毛病
页眉页脚配置html脚本转为json后
例子,用https://uutool.cn/html2json/ 工具可转换,转换才能通过api/pdf发送命令的。
{ name: (original ? "记录" : "报告") + rep?.isp?.no,
singleTab: true,
lay: {
head: [
'<div style=\"position: relative; width:100%; text-align:center; border-bottom: 1pt solid #eeeeee; margin: 3.5mm 0px 10px; font-size: 10pt\">',
<div style=\\"position: absolute; width:100%; text-align:left; bottom: 5px; left: 50px;\\">报告No: ${rep?.isp?.no}</div></div>
],
foot: [
'<div style=\"position: relative; width: 100%; text-align: left; border-top: 1pt solid #eeeeee; margin: 10px 0px 1.5mm; font-size: 8pt;\">',
'<div style=\"position: absolute; width: 100%; text-align: center; top: 5px;\">共~pageNumber~页 / 第~totalPages~页'
],
},
files: [
{
url,
out: tmp-${rep?.isp?.no} + (original ? "-O" : ""),
headFrom: 3,
frNo: 3,
},
] }
其中 -NOT_DISPLAY- 指示若没有页码的就不显示相关局部部分。
注意适用性
本文书打印转换器只能适用单用户在客户本机用,每次执行一个打印指令,不要并行发出指令,本机工作目录也是临时文件,针对当前指令适用的,不能存放无关文件。 本转换器console命令输出窗口可实时观察到当前打印转换指令的执行过程输出提示,同时目标浏览器也会新开启浏览窗口,这些由本转换器自动开启的浏览窗口实际上 就是转换读取页面的过程,若无法访问页面或没有登录目标url网站的就能体现在这些窗口中,每一个url转换生成了相应对应pdf之后就失去用处了。 本转换器内部使用了CDP协议Chrome DevTools Protocol连接的浏览器进程,暂时没发现安全性问题。
配置文件
本地较为固定的参数设置,在/config/default.json文件,例子如下的,注意自定义纸张没有方向的说法,"w"宽度,"h"高度,单位英寸。 { "base_path": "E:\临时\web打印\pdfs", "default_file": "合并后的文档", "size":[ {"name":"D8", "css": "4in 6in","w": 4,"h": 6}, {"name":"D4", "css": "10.4in 12.6in","w": 10.4,"h": 12.6} ] }
拒绝连接的
对Chrome 右键 点选 以管理员身份运行; 前提需 有npm 就是 node环境的; 复制目录+ 还需安装 npm ci --only=production 新版本需无头的 "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9872 --headless
动态布局问题
只用css做动态的组件和用了js脚本做动态布局的组件在打印时刻不同,比如"customize-easy-ui-component"库的LineColumnFlex和LineColumn的差别即使这样, 前者在打印时刻需要约束浏览器窗口的宽度为纸张输出的宽度差不多的大小,后者可打印页数就可能和内容页数不一致,后者只用css的就不会有这个麻烦。 就算同一个组件有可能出现:同一次打印出现两种布局状态。比如这样的:<LineColumnFlex 1> {useMediaQuery({query: 'print'}) && <LineColumnFlex 2>}的, 前面一个是js按照浏览器打印触发之前的div宽度来布局的有5列,然而后面哪一个是按照最终纸张输出宽度来做布局的才2列,完全不一样了!但是后面第二个组件可能输出不完整的, 因为打印纸张的输出页数实际在useMediaQuery({query: 'print'})逻辑条件成立以前就敲定了可打印纸张数量!!所以有很大问题。js动态代码简单,css动态写代码麻烦。 就接着这个例子讲:用{useMediaQuery({query: 'print'})&&逻辑嵌套的哪些内容,就算我约束了浏览器宽度为纸张宽度以后,实际上在打印敲定输出页数时间这些逻辑嵌套的 需要打印内容实际上也并没有计算在立刻敲定输出页数之内的,因此也必然导致打印页数丢失或不够的问题的,这个情况必须用css,除非不打印比打印语境内容占用高度还少的话。
发布更新
工具包需要发布,工程目录:page2pdf-server/packages/types 执行 npm publish 发布到npm
