使用pdfKit与html-to-text生成PDF时HTML样式不生效的求助
问题:HTML样式无法在pdfKit+html-to-text生成的PDF中体现
我目前用pdfKit和html-to-text工具从HTML生成PDF,但HTML里的样式完全无法在最终PDF里显示。接受两种解决方案:要么修复当前工具的问题,要么替换成其他工具。
注:之前用过Puppeteer(耗时太长已弃用)、html-pdf(同样有样式问题),请不要推荐这两个。
现有代码
const PDFDocument = require("pdfkit"); const {convert} =require('html-to-text'); const {PassThrough}=require("stream"); const generateCombinedCertificatePDFBuff = (context, compiledHTML) => { return new Promise(async (resolve, reject) => { try { const doc = new PDFDocument(); const buffer = []; const stream = new PassThrough(); doc.pipe(stream); doc.text(convert(compiledHTML)); doc.end(); stream.on("data", (chunk) => buffer.push(chunk)); stream.on("end", () => resolve(Buffer.concat(buffer))); stream.on("error", (err) => reject(err)); } catch (err) { console.log(err); reject(err); } }); };
解决方案
方案一:修复当前工具链的样式问题
html-to-text的核心是将HTML转成纯文本,天然会丢弃所有样式,这是样式丢失的根本原因。要保留样式,需替换html-to-text,改用能解析HTML样式并适配pdfKit的工具:
- 使用
pdfkit-html插件:该工具可直接将带内联样式/外部CSS的HTML转换成pdfKit可识别的指令,保留样式。
修改后的代码示例:const PDFDocument = require("pdfkit"); const { htmlToPDFDocument } = require("pdfkit-html"); const { PassThrough } = require("stream"); const generateCombinedCertificatePDFBuff = (context, compiledHTML) => { return new Promise(async (resolve, reject) => { try { const doc = new PDFDocument(); const buffer = []; const stream = new PassThrough(); doc.pipe(stream); // 处理带样式的HTML await htmlToPDFDocument(doc, compiledHTML); doc.end(); stream.on("data", (chunk) => buffer.push(chunk)); stream.on("end", () => resolve(Buffer.concat(buffer))); stream.on("error", (err) => reject(err)); } catch (err) { console.log(err); reject(err); } }); }; - 注意:确保HTML样式为内联样式,或通过
pdfkit-html配置引入外部CSS文件,才能被正确解析。
方案二:替换为其他工具
推荐以下两款工具,样式还原度高且性能优于Puppeteer:
- wkhtmltopdf:基于WebKit引擎的命令行工具,能精准解析HTML和CSS,生成的PDF样式还原度高。可通过Node.js封装包
wkhtmltopdf-node调用:
安装:npm install wkhtmltopdf-node
示例代码:const wkhtmltopdf = require("wkhtmltopdf-node"); const generateCombinedCertificatePDFBuff = (context, compiledHTML) => { return new Promise((resolve, reject) => { const options = { input: compiledHTML, output: false, // 返回Buffer而非文件 options: { pageSize: "A4", margin: { top: "10mm", right: "10mm", bottom: "10mm", left: "10mm" } } }; wkhtmltopdf(options, (err, buffer) => { if (err) reject(err); else resolve(buffer); }); }); }; - html-pdf-chrome:基于Chrome无头模式,相比Puppeteer启动更快,样式还原准确(需环境中安装Chrome/Chromium):
安装:npm install html-pdf-chrome
示例代码:const htmlPdf = require("html-pdf-chrome"); const generateCombinedCertificatePDFBuff = (context, compiledHTML) => { return htmlPdf.create(compiledHTML, { port: 9222, // 可指定Chrome端口 printOptions: { format: "A4", margin: { top: 10, right: 10, bottom: 10, left: 10 } } }).then((pdf) => pdf.toBuffer()); };
内容的提问来源于stack exchange,提问作者Muhammad Hamza Maqsood
相关产品推荐
相关产品推荐

