当前位置: 首页 > news >正文

生成PDF文件:从html2canvas和jsPdf渲染到Puppeteer矢量图

刚刚实现而已:第一次明白,双击或file:///打开html文件,居然和从localhost:3000打开同一个html文件有本质的区别。

字体居然还能以Base64代码嵌入到网页,只是太大太笨。

需要安装node.jsnpm安装更多依赖:
npm init -y
npm install express puppeteer uuid cors

在这里插入图片描述在这里插入图片描述需要管理员在命令行:
npm start
node server.js (后台、后端,也涉及很多繁琐的设置)
如果不是有大语言模型手把手交,效率会低不少。

反复测试,仍不完美。但server.js应该是可以固定下来了:

const express = require('express');
const puppeteer = require('puppeteer');
const path = require('path');
const fs = require('fs').promises;
const { v4: uuidv4 } = require('uuid');
const cors = require('cors');

const app = express();
app.use(express.static('public'));
const port = 3000;

// 配置 CORS
app.use(cors({
    origin: 'http://localhost:3000', // 明确允许客户端来源
    methods: ['GET', 'POST'],
    allowedHeaders: ['Content-Type']
}));

app.use(express.json({ limit: '10mb' }));
app.use(express.static(path.join(__dirname, 'public')));

app.get('/', (req, res) => {
    res.send('服务器运行正常!请访问 /index.html 或点击“打印到 PDF”按钮生成 PDF。');
});

app.post('/generatepdf', async (req, res) => {
    console.log('Received request to generate PDF');
    const { html } = req.body;

    if (!html) {
        console.error('Missing HTML content in request body');
        return res.status(400).send('Missing HTML content');
    }

    try {
        console.log('Launching Puppeteer...');
        const browser = await puppeteer.launch({
            headless: true,
            args: ['--no-sandbox', '--disable-setuid-sandbox']
        });
        console.log('Puppeteer launched successfully');
        const page = await browser.newPage();
        console.log('Setting page content...');
        await page.setContent(html, { waitUntil: 'networkidle0' });
        console.log('Page content set');
        console.log('Generating PDF...');
        const pdfBuffer = await page.pdf({
            format: 'A4',
            printBackground: true,
            preferCSSPageSize: true
        });
        console.log('PDF buffer size:', pdfBuffer.length);
        await browser.close();
        console.log('PDF generated successfully');

        // 保存 PDF 文件用于调试
        const filename = `jingyesi-output-${uuidv4()}.pdf`;
        await fs.writeFile(path.join(__dirname, filename), pdfBuffer);
        console.log(`PDF saved to ${filename} for debugging`);

        // 设置响应头并发送 PDF(使用二进制发送)
        res.set({
            'Content-Type': 'application/pdf',
            'Content-Length': pdfBuffer.length,
            'Content-Disposition': 'attachment; filename="jingyesi.pdf"'
        });
        res.end(pdfBuffer, 'binary'); // 使用 res.end 确保二进制数据发送
    } catch (error) {
        console.error('Failed to generate PDF:', error);
        res.status(500).send('Failed to generate PDF: ' + error.message);
    }
});

app.listen(port, () => {
    console.log(`服务器运行在 http://localhost:${port}`);
});

要保持 localhost:3000 后台服务器一直开启状态。访问本地其它资源的虚拟网页仍然要http-server --c-1 -cors 另外开或者修改地址之后也从同一个服务器指向的文件夹实现

不完美的地方主要是,Puppeteer 对嵌入字体的支持比较弱,Base64代码把整个字体文件打包进去之外太笨拙,引用网络字体似乎效果不理想。

相关文章:

  • Android Handler 通过线程安全的 MessageQueue 和底层唤醒机制实现跨线程通信
  • 【嵌入式学习】如何利用gitee管理记录学习内容
  • 多线程—进程与线程
  • 【软考-架构】8.2、开发方法-TPC-MIS-DSS
  • RSI 量化策略实战指南:基于 iTick 报价源的 Python 实现
  • 卷积神经网络 - 卷积层
  • 库的制作与原理 linux第课
  • LORA的AB矩阵是针对Transformer的多头还是MLP
  • 台式机电脑组装---电脑机箱与主板接线
  • 线程池的拒绝策略适用场景思考
  • 网络编程套接字【端口号/TCPUDP/网络字节序/socket编程接口/UDPTCP网络实验】
  • 双曲空间学习记录
  • TypeScript Symbols 深度解析:在 Vue3 中的高级应用实践
  • 人脸识别-检测数据集
  • C++ :顶层const与底层const的区别
  • 【Linux网络(三)】网络基础套接字
  • 【CXX-Qt】1.5 使用CMake构建
  • 《深入理解AOP编程:从基础概念到Spring实现》
  • C++中std::shuffle 的使用
  • MySQL 多列 IN 查询详解:语法、性能与实战技巧
  • 欧盟委员会计划对950亿欧元美国进口产品采取反制措施
  • 见微知沪|优化营商环境,上海为何要当“细节控”自我加压?
  • 第1现场 | 50多年来首次!印度举行大规模民防演习
  • 上海乐高乐园度假区将于7月5日开园
  • 五一假期上海楼市延续向好态势,成交量同比增加36%
  • 《黎明的一切》:与正常世界脱轨后,我选择不再回去