Docker 平台 NodeJs Puppeteer实现html转pdf

字节探险家说
• 阅读 114

Docker 平台 NodeJs Puppeteer实现html转pdf

1. 背景

PDM系统中有需求工艺单需要打印成PDF(客户对细节要求极高),当时出了5个方案:

  1. 从DOM制作屏幕截图 html2canvas jspdf 文字无法拷贝
  2. 使用PDF库 jsPDF 或 PDFKit 按组件一个一个拼凑,不合适已有html的打印模板方式
  3. CSS打印规则,调用浏览器打印,pdf 文件导入到系统,操作繁琐
  4. itext (目前用的) 和spire功能强大,但商业用途需收费,wkhtmltopdf开源免费,后端生成,黑匣子,后端开发前端代码,可视化麻烦通过模板生成PDF的实际效果和模板效果相差较大,修改起来不好把握
  5. 基于Node.js的Puppeteer和HeadlessChrome 展示效果与实际生成的PDF接近

使用方案5是可以借助puppeteer调用headless浏览器生成PDF,对css的支持度很高,PDF能很大限度反应模板的样式(对css支持度很高),前端对模板的控制度更高,支持dom操作,以下是模板样式和PDF样式对比:

生成的pdf文件样式和编写的html模板样式一致度较高,可以让前端编写模板文件实时查看html内容样式,改完之后用该模板调用后端的node服务生成的pdf模板能较高程度的还原模板内容,前端可以通过模板引擎如EJS(类似于当前方案后端技术的freemarker模板)生成模板执行一些复杂的dom操作和样式控制。

2. 所需依赖

npm install express jsdom puppeteer

express: 用来和业务系统通信,返回pdf流给业务系统

jsdom: 解析DOM,在生成pdf的时候要让前端可以自定义pdf的页头页尾

puppeteer: 调用headless生成PDF

3. 核心代码

genPdfFile.js

const puppeteer = require('puppeteer');
const fs = require('fs');
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
let browserInstance;

async function getBrowserInstance() {
    if (!browserInstance) {
        browserInstance = await puppeteer.launch({
            headless: true,
            args: ['--no-sandbox', '--disable-setuid-sandbox']
        });
    }
    return browserInstance;
}

async function generatePDFFromHTML(htmlString) {
    try {
            // 启动Puppeteer
    const browser = await getBrowserInstance();
    const page = await browser.newPage();
         // 页眉
        let headerTemplate = "";
        // 页脚
        let footerTemplate = "";
        {
            // 构建页眉
            console.log("headerTemplate");
            let dom = new JSDOM(htmlString);
            let document = dom.window.document;
            const elementsToRemove = document.querySelectorAll(".page_start");
            if(elementsToRemove.length > 0) {
                headerTemplate = elementsToRemove[0].outerHTML;
            }
            elementsToRemove.forEach(el => el.parentNode.removeChild(el));  
            updatedHtmlString = dom.serialize();
        }
    
        {
            // 构建页脚
            console.log("footerTemplate");
            dom = new JSDOM(updatedHtmlString);
            document = dom.window.document;
            const endelementsToRemove = document.querySelectorAll(".page_end");
            if(endelementsToRemove.length > 0) {
                footerTemplate = endelementsToRemove[0].outerHTML;
            }
            endelementsToRemove.forEach(el => el.parentNode.removeChild(el));  
            updatedHtmlString = dom.serialize();
        }
        
        // 设置HTML内容并生成PDF的Buffer
        await page.setContent(updatedHtmlString);

        // 设置 PDF 选项
        const pdfOptions = {
            path: 'example.pdf',
            format: 'a4',
            displayHeaderFooter: true,
            headerTemplate,
            footerTemplate,
            margin: {
                top: '60px',
                bottom: '20px',
                left: '20px',
                right: '50px'
            },

        };
        // 生成 PDF
         // 如果要生成带着 screen media的pdf,在page.pdf() 前面先调用 page.emulateMedia('screen')
        const pdfBuffer = await page.pdf(pdfOptions);
        return pdfBuffer;
    } catch(error) {
        console.log(error);
    }
}

module.exports = {
    getBrowserInstance,
    generatePDFFromHTML
}

4. DockerFile

FROM ghcr.io/puppeteer/puppeteer:latest

MAINTAINER weiqlog@126.com

USER root

RUN mkdir -p /pdfG

WORKDIR /pdfG

COPY package*.json ./

COPY . .

RUN npm instal

EXPOSE 10030

ENTRYPOINT ["node", "main.js", "10030"]

镜像地址:https://hub.docker.com/r/1505774577/html_to_pdf

使用:

docker pull 1505774577/html_to_pdf:1.0.0.dev
docker run -d -p 10030:10030 --cap-add=SYS_ADMIN 1505774577/html_to_pdf:1.0.0.dev

本文由mdnice多平台发布

点赞
收藏
评论区
推荐文章
good123 good123
3年前
PDF转WORD为什么是历史难题
PDF转Word是一个非常非常普遍的需求,可谓人人忌危,为什么如此普遍的需求,却如此难行呢,还得看为什么会有这样的一个需求:PDF文档遵循iOS32000的规范是由Adobe公司推出的文档格式,之所以应用如此广泛,是因为PDF精确定位了每个字符的坐标、根据坐标绘制的各种形状,使用PDF格式传输和打印文档可以保证格式的一致性,然后很多PDF文件是可用于阅
秋桐 秋桐
2年前
通过Java实现Word转PDF
Word转为PDF是非常常见的一种格式转换。通过转换可以将文档以更为稳定的格式进行保存,避免他人随意修改格式和内容。其实Word转PDF并不难,除了直接转换外也可以通过编程的方式来实现。网上相关的教程分享也很多。今天想介绍一个JavaWord组件——Fre
Wesley13 Wesley13
3年前
Java iText+FreeMarker生成PDF(HTML转PDF)
1.背景在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等。方便用户查看,下载,打印。目前常用的解决方案是,把相关数据信息,生成对应的pdf文件返回给用户。!(https://static.oschina.net/uploads/space/2017/0507/202942_6jpZ_14059
Stella981 Stella981
3年前
PHP imagick 实现 PDF 转 图片
1、ImageMagick安装官网(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.imagemagick.org%2Fscript%2Finstallsource.php)tarzxvfImageMagick.tar.gzC/usr/lo
Wesley13 Wesley13
3年前
P2P技术揭秘.P2P网络技术原理与典型系统开发
Modular.Java(2009.06)\.Craig.Walls.文字版.pdf:http://www.t00y.com/file/59501950(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.t00y.com%2Ffile%2F59501950)\More.E
Stella981 Stella981
3年前
PDFJs 在线预览插件
0.A.到官网https://mozilla.github.io/pdf.js/getting\_started/download下载最新版本B部署到IIS中访问pdf.js/web/viewer.html查看效果1\.后台返回pdf的base64字段,用pdf.js展示https://www.jianshu.co
一次单据图片处理的优化实践 | 京东物流技术团队
1引言日常开发中接到这样的需求,上游系统请求获取一张A4单据用于仓库打印及展示,要求PNG图片格式,但是我们内部得到的单据格式为PDF,需要提取PDF文档的元素并生成一张PNG图片。目前已经有不少开源工具实现了这一功能,我们找了网上使用比较多的Apache
秋桐 秋桐
1年前
如何通过Python代码旋转PDF页面
日常处理PDF文档时,我们时常会遇到页面颠倒、很难正常阅读或打印的情况。在这种情况下,我们可以通过旋转页面来调整文档的方向。旋转时,也可以根据具体情况,选择顺时针或逆时针旋转特定的角度,以使页面内容更加清晰可读或适应特定的显示需求。这一功能可以通过PDF处理工具或者库来实现。这篇文章将介绍如何使用PDF库在Python平台上旋转文档页面。
源码补丁神器—patch-package
一、背景vue项目中使用第三方插件预览pdf,书写业务代码完美运行,pdf文件内容正常预览无问题。后期需求有变,业务需求增加电子签章功能。这个时候pdf文件的内容可以显示出来,但是公司的电子签章无法显示。这令人沮丧,因为已经编写了许多特定于此依赖项的代码,
移动端提高pdf预览清晰度
背景:移动端预览PDF文件,通用的解决方案是使用vuepdf插件,其内置pdf.js,原理是基于HTML5的标签,通过将PDF文件转换为图片或来实现对PDF文件的预览,插件好使没毛病😆,但是如果我们的需求是要在移动端预览内容很密集的文件时,预览效果就不理
京东云开发者 京东云开发者
4个月前
源码补丁神器—patch-package
作者:张浩一、背景vue项目中使用第三方插件预览pdf,书写业务代码完美运行,pdf文件内容正常预览无问题。后期需求有变,业务需求增加电子签章功能。这个时候pdf文件的内容可以显示出来,但是公司的电子签章无法显示。这令人沮丧,因为已经编写了许多特定于此依赖
字节探险家说
字节探险家说
Lv1
小楼一夜听春雨,深巷明朝卖杏花。
文章
10
粉丝
0
获赞
0