• home > webfront > ECMAS > nodejs >

    nodejs后端PDF生成预研方案:DPF模板预填VS 浏览器DPF生成

    Author:zhoulujun Date:

    PDF后端生成有2种形式,分为模板生成:适合简单的表单内容DPF生成。只需要提前筹备模板,后端填数据即可优点:技术简单缺点:前端样式负责

    PDF后端生成有2种形式,分为

    1. 模板生成:适合简单的表单内容DPF生成。只需要提前筹备模板,后端填数据即可

      • 优点:技术简单

      • 缺点:前端样式负责的情况下,无法与前端页面保持一致,且通常无法复用前端页面。

    2. 浏览器生成方案

      • 优点:完全复用前端页面组件,与用户所见页面保持一致

      • 缺点: linux部署无头浏览器(如Puppeteer)复杂,而且设计导授权认证等逻辑的改造

    DPF模板方案

    PDF模板方案又分为2种,分为DPF预填(已有DPF,填充数据)与 PDF模板库生成

    DPF预填

    最场景就是 PO、PA 在产品层,通过word等工具转出DPF

    image.png


    使⽤Adobe Acrobat DC创建模板

    使用Adobe Acrobat DC,创建表单
    image.png

    具体请参看《adobe acrobat pro制作DPF表单模板

    填写DPF表单

    有了DPF表单后,就是读取文件,填写表单就可以了

    比如可以使用pdf-lib 库

    const templateBytes = await fs.promises.readFile(templatePath);
    const pdfDoc = await PDFDocument.load(templateBytes);
    const form = pdfDoc.getForm();

    demo代码

    const { PDFDocument, StandardFonts } = require('pdf-lib');
    const fs = require('fs');
    const fontkit = require('@pdf-lib/fontkit')
    let pdfDoc
    let font
    async function fillPdfForm(templatePath, outputPath, data) {
      const templateBytes = await fs.promises.readFile(templatePath);
      const fontBytes = await fs.promises.readFile('xxx.ttf');
      pdfDoc = await PDFDocument.load(templateBytes);
      pdfDoc.registerFontkit(fontkit);
      font = await pdfDoc.embedFont(fontBytes);
      const form = pdfDoc.getForm();
     
      for (const fieldKey in data) {
        const field = form.getTextField(fieldKey);
        if (field) {
          field.setText(data[fieldKey]);
          field.updateAppearances(font)
        }
      }
     
      const modifiedPdfBytes = await pdfDoc.save();
     
      await fs.promises.writeFile(outputPath, modifiedPdfBytes);
    }

    这种方案对于开发来说最简单,只需按照表单提供数据即可

    DPF模板生成

    这种就是在制作前端页面的时候,使用 pdf模板库(好比taro开发小程序,图的就是编译转换),比如

    https://react-pdf.org/

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { PDFViewer,renderToStream } from '@react-pdf/renderer';
    
    const styles = StyleSheet.create({
      page: { flexDirection: 'row',backgroundColor: '#E4E4E4' },
      section: { margin: 10,    padding: 10,}
    });
    const App = () => (
      <PDFViewer>
        <Document>
        <Page size="A4" style={styles.page}>
          <View style={styles.section}>
            <Text>Section #1</Text>
          </View>
          <View style={styles.section}>
            <Text>Section #2</Text>
          </View>
        </Page>
      </Document>
      </PDFViewer>
    );
    
    renderToStream(<App />);

    具体参看官网


    这种模式,也能过做到页面与PDF模板同一套

    但是,对于已经开发好了的页面,在来开发,重构成本还是非常大的!

    无头浏览器生成PDF

    phantomjs已经成为弃子,puppeteer 现在是首选

    puppeteer生成PDF

    其是和浏览器按Ctrl+P 另存为PDF是一样的

    const puppeteer = require('puppeteer');
    (async () => {
      // 启动浏览器
      const browser = await puppeteer.launch();
      const page = await browser.newPage();
      
       // 设置要生成的网页内容
      await page.setContent(`
        <h1>Hello, World!</h1>
        <p>This is a sample PDF generated by Puppeteer.</p>
      `);
      
      // 直接打开要截图的网页
      //await page.goto(pageUrl)
      
      await page.pdf({
        path: 'output.pdf', // 输出文件路径
        format: 'A4', // 页面大小
      });
    })();

    这个方案看似简单省事,但是需要解决问题也蛮多

    登录验证问题

    截图表单内容,一般需要登录态才能访问,这个时候可以setCookie 等方式访问。

    关键是如何获取cookie?

    第二个,可能因为授权问题,业务逻辑层面也需要改变!

    Puppeteer安装问题

    Puppeteer 在docker 容器里面,一般没意chrome浏览器,这个时候需要手动安装

    一般推荐直接使用 本地配置好的镜像,或者使用第三方封装好镜像

    Puppeteer网络访问与安全问题

    大部分的容器集群一般网络白名单制度,这个时候防火墙层面审批,…………

    第二个是Puppeteer 本身 chrome的sandbox问题 越权问题等审核……

    总之,这个方向,安全审批层面,……



    综合上面4总方案,对于开发者而言,更推荐使用DPF表单模板方案

    开发只需要准备数据映射接口即可……

    关于DPF的维护层面,交给产品……









    参考文章:

    通过pdf模板,填充内容,生成pdf文件---JAVA https://www.cnblogs.com/jthr/p/16229784.html

    通过pdf模板,填充内容,生成pdf文件---JAVA https://www.cnblogs.com/jthr/p/16229784.html



    转载本站文章《nodejs后端PDF生成预研方案:DPF模板预填VS 浏览器DPF生成》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/JS-Server/9447.html

    下一篇:最后一页