Node.js PDFKit如何传入HTML代码作为函数参数生成PDF
结论
PDFKit 没有内置可直接传入HTML代码并自动渲染对应内容的原生函数。
PDFKit本身是底层PDF生成库,核心API围绕基础绘制能力设计(文本、矢量图形、图片、基础样式设置),没有内置HTML解析、CSS样式计算、复杂排版(浮动、流式布局、表格等)的引擎,无法直接识别HTML标签规则完成渲染。
仅基于PDFKit的实现方案
如果不能引入额外的HTML转PDF第三方依赖,可以通过「HTML标签规则映射+手动调用PDFKit API」的方式实现简易HTML渲染,适合结构简单、标签范围可控的场景(比如基础富文本、简单文章内容),具体实现逻辑如下:
- 第一步:确定需要支持的HTML标签范围,提前做好标签和PDFKit API的映射规则,比如:
- 块级标签:
<h1>~<h6>对应不同字号的加粗字体、段后间距;<p>对应正文字号、行间距;<br>对应换行;<li>对应缩进+列表标记 - 行内标签:
<b>/<strong>对应切换粗体;<i>/<em>对应切换斜体;<u>对应开启下划线;<font color="xxx">对应设置字体颜色
- 块级标签:
- 第二步:编写轻量解析逻辑,把传入的HTML字符串拆分成带样式标记的内容块,不需要实现完整的HTML解析器,简单场景用正则替换、标签分割即可完成基础标签的识别。
- 第三步:遍历解析后的内容块,根据每个块的样式标记,依次调用PDFKit的
font()、fontSize()、fillColor()、text()、moveDown()等API完成绘制,利用PDFKit自带的文本自动换行、流式排版能力,不需要手动计算每行文本的坐标。
简易实现示例代码
const PDFDocument = require('pdfkit'); const blobStream = require('blob-stream'); /** * 基于PDFKit的简易HTML渲染方法 * @param {PDFDocument} doc PDFKit实例 * @param {string} html 待渲染的HTML字符串 * @param {number} startX 内容起始X坐标 * @param {number} startY 内容起始Y坐标 */ function renderSimpleHtml(doc, html, startX = 100, startY = 100) { doc.x = startX; doc.y = startY; // 标签预处理,替换为自定义标记方便拆分 let processed = html .replace(/<h1>(.*?)<\/h1>/gis, '\n[block:h1]$1[/block]\n') .replace(/<p>(.*?)<\/p>/gis, '\n[block:p]$1[/block]\n') .replace(/<br\s*\/?>/gis, '\n') .replace(/<b>(.*?)<\/b>/gis, '[style:b]$1[/style]') .replace(/<strong>(.*?)<\/strong>/gis, '[style:b]$1[/style]') .replace(/<i>(.*?)<\/i>/gis, '[style:i]$1[/style]') .replace(/<em>(.*?)<\/em>/gis, '[style:i]$1[/style]') .replace(/<u>(.*?)<\/u>/gis, '[style:u]$1[/style]'); // 拆分内容块 const blocks = processed.split('\n').filter(item => item.trim()); blocks.forEach(block => { // 渲染一级标题 if (block.startsWith('[block:h1]')) { const text = block.replace('[block:h1]', '').replace('[/block]', '').replace(/\[\/?style:[biu]\]/g, ''); doc.font('Helvetica-Bold').fontSize(25).fillColor('#000').text(text, { continued: false }); doc.moveDown(1); return; } // 渲染段落 if (block.startsWith('[block:p]')) { let text = block.replace('[block:p]', '').replace('[/block]', ''); // 识别行内样式 const hasBold = /\[style:b\]/.test(text); const hasItalic = /\[style:i\]/.test(text); const hasUnderline = /\[style:u\]/.test(text); // 清理样式标记 text = text.replace(/\[\/?style:[biu]\]/g, ''); // 匹配对应字体 let font = 'Helvetica'; if (hasBold && hasItalic) font = 'Helvetica-BoldOblique'; else if (hasBold) font = 'Helvetica-Bold'; else if (hasItalic) font = 'Helvetica-Oblique'; // 渲染段落 doc.font(font).fontSize(12).fillColor('#333').text(text, { continued: false, lineGap: 4, underline: hasUnderline }); doc.moveDown(0.5); return; } // 普通文本直接渲染 doc.font('Helvetica').fontSize(12).fillColor('#333').text(block.replace(/\[\/?style:[biu]\]/g, '')); }); } // 原有初始化逻辑 const doc = new PDFDocument(); const stream = doc.pipe(blobStream()); // 测试渲染HTML const demoHtml = ` <h1>PDFKit渲染HTML测试</h1> <p>这是普通正文内容,其中包含<b>加粗文本</b>、<i>斜体文本</i>、<u>下划线文本</u>,以及<b><i>同时加粗+斜体的文本</i></b>。</p> <p>PDFKit会自动处理长文本换行,不需要手动计算每行宽度,段落之间会自动保留预设的间距。</p> `; renderSimpleHtml(doc, demoHtml); doc.end();
方案说明
- 上述示例只实现了最基础的标签支持,你可以根据业务需求扩展解析规则,比如支持列表、字体颜色、对齐方式、超链接、图片等标签,本质都是把HTML标签的表现,映射为PDFKit对应的API调用即可。
- 该方案的局限性是无法兼容复杂HTML/CSS效果,比如浮动布局、Flex布局、复杂表格、嵌套层级极深的标签、外部引入的CSS规则等,这类复杂场景如果只靠手动映射规则开发成本会非常高;如果只是渲染简单富文本内容,该方案完全可以满足需求,且没有额外依赖。
内容的提问来源于stack exchange,提问作者Chandra Shekhar
相关产品推荐
相关产品推荐

