关于 boxpdf-html
boxpdf-html 使用 boxpdf 库将编写好的 HTML 转为静态 PDF,适用于发票和报告等文档。它还提供 MCP 服务,包含 PDF 渲染工具和库文档指导。
主要功能
- 01通过命令行和 API 将 HTML 转为 PDF
- 02MCP 转换工具与库使用指导
- 03CSS 诊断及不支持样式报告
- 04自定义嵌入字体与图像处理
- 05大型文档流式转换
- 06命令行 PDF 密码加密
适用场景
- 01根据发票或收据 HTML 生成 PDF
- 02渲染文档使用的 Tailwind CSS
- 03增量转换大型 HTML 归档
- 04为 Agent 提供 PDF 生成指导
MCP 相关
stdio MCP 服务提供 `html_to_pdf`,可渲染 HTML 和可选 CSS;`boxpdf_docs` 提供针对性的库使用指导。服务还提供指南、README 和模板资源。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
2收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| css | string | 否 | 渲染前注入的额外样式表(例如,已编译的 Tailwind 输出)。 |
| html | string | 是 | HTML 标记。可包含 <style> 块和内联样式。 |
| size | enum | 否 | 每页条目数。Letter | Legal | Tabloid | A4 | A5 | A6 |
| debug | boolean | 否 | 绘制 boxpdf 调试叠加层。 |
| fonts | object | 否 | 可选的 TTF/OTF 文件路径,用于嵌入字体,以替代内置的 Helvetica 字体系列。 |
| fonts.bold | string | 否 | |
| fonts.italic | string | 否 | |
| fonts.regular | string | 否 | |
| fonts.boldItalic | string | 否 | |
| margin | number | 否 | PDF 页面边距,单位为点。 |
| baseUrl | string | 否 | 用于解析相对 <img> 和 background-image URL 的目录或 URL。默认为工作目录。 |
| outputPath | string | 否 | PDF 的写入位置(可使用相对于 cwd 的路径)。如果省略,PDF 将以内联 base64 资源形式返回。 |
| allowRemote | boolean | 否 | 允许获取 http(s) 图片。默认关闭,以防止 SSRF。 |
详细介绍
@boxpdf/html-reader
基于 @boxpdf/writer 构建的易读 HTML 转 PDF 渲染工具。适用于发票、收据、报告、电子邮件,以及其他需要生成实用静态 PDF、而非模拟浏览器像素级效果的自编 HTML 文档。
npm install @boxpdf/html-reader @boxpdf/writer pdf-lib
原有的 boxpdf-html 软件包和 boxpdf-html 命令仍受支持。它们与 @boxpdf/html-reader 使用相同的构建版本发布。新项目应使用带作用域的软件包;现有项目无需更改。
CLI
直接渲染 HTML 文件:
npx @boxpdf/html-reader invoice.html invoice.pdf
带作用域的软件包也提供了更短的命令名称 html-reader。
使用生成的 Tailwind CSS:
npx tailwindcss -i ./tailwind.css -o ./dist/tailwind.css --minify
npx @boxpdf/html-reader invoice.html invoice.pdf --css ./dist/tailwind.css
对于非常大的输入,请添加 --stream:
npx @boxpdf/html-reader archive.html archive.pdf --stream
type archive.html | npx @boxpdf/html-reader - archive.pdf --stream
流式处理会对 HTML 进行两次有界遍历:第一次处理 CSS、字体和图片,第二次进行增量布局并输出 PDF。标准输入会先写入临时文件,以便重新打开。只有转换成功后,输出才会替换目标文件。此路径要求使用 boxpdf 1.12.0 或更高版本。
使用 PDF 2.0 AES-256 密码加密:
BOXPDF_PASSWORD='open me' \
npx @boxpdf/html-reader invoice.html invoice.pdf --password-env BOXPDF_PASSWORD
--password-env 接受环境变量名称。该变量必须已设置为非空密码。密码值不会作为命令参数接收,因此不会出现在命令行或进程列表中。
使用自定义字体和本地图片:
npx @boxpdf/html-reader invoice.html invoice.pdf \
--font ./Inter-Regular.ttf \
--bold-font ./Inter-Bold.ttf \
--font-family 'Inter=normal:Inter-Regular.ttf,bold:Inter-Bold.ttf'
实用标志:
html-reader <input.html> <output.pdf>
html-reader - <output.pdf> # read HTML from stdin
html-reader input.html output.pdf --css app.css
html-reader input.html output.pdf --base-url ./public
html-reader input.html output.pdf --password-env BOXPDF_PASSWORD
html-reader input.html output.pdf --debug
html-reader input.html output.pdf --unsupported-css
html-reader input.html output.pdf --profile
html-reader input.html output.pdf --stream
CLI 默认使用 pdf-lib 内置的 Helvetica 字体系列。对于生产输出,如果需要匹配品牌风格、覆盖 Unicode 字符或保证精确度量,请使用实际嵌入的字体。
MCP 服务
boxpdf-html mcp 是面向 AI Agent 的标准输入输出 MCP 服务。它开箱即用:提供 html_to_pdf 工具和完整的 boxpdf 库文档,因此 Agent 无需再添加第二个服务。
claude mcp add boxpdf-html -- npx -y @boxpdf/html-reader mcp
工具
html_to_pdf— 将 HTML 字符串(以及可选的css)渲染为 PDF。写入outputPath,或以内联 base64 资源的形式返回 PDF。始终返回warnings和unsupportedCss诊断信息,供 Agent 修正输入。- 参数:
html(必需)、css、outputPath、size(Letter/A4/Legal/Tabloid,默认值为Letter)、margin(默认值为 40)、baseUrl、fonts: { regular, bold, italic, boldItalic }(TTF/OTF 路径)、allowRemote(默认值为false——除非启用,否则会阻止获取 http(s) 图片)、debug。
- 参数:
boxpdf_docs— 直接使用库构建 PDF 的专项指南。topic:quickstart(默认值)、fonts、themes、tables、pagination、streaming、html-api、cloudflare。
资源:boxpdf-html://guide、boxpdf-html://readme、boxpdf://readme,以及五个 boxpdf://templates/<name> 源(receipt、boarding-pass、resume、order-confirmation、certificate)。
该服务不运行 JavaScript,且默认不会发出网络请求。outputPath 会以 Agent 的文件系统权限写入文件;如果未指定该参数,超过 1 MB 的 PDF 会以摘要形式返回,而不会以内联形式返回。
API
htmlToPdf — 一次调用即可获取字节数据
htmlToPdf(html, options?) 是最简单的方式:它会创建文档、嵌入字体、进行渲染并返回 PDF 字节数据。字体默认使用内置的 Helvetica 字体系列,因此最简调用无需任何设置。
import { htmlToPdf } from "@boxpdf/html-reader";
const bytes = await htmlToPdf("<h1>Invoice</h1><p>Thanks for your order.</p>");
对于生产输出,请传入嵌入字体(通过 loadFont 加载)和 resolveImage 回调:
import { readFile } from "node:fs/promises";
import { PDFDocument } from "pdf-lib";
import { loadFont, loadImage } from "@boxpdf/writer";
import { htmlToPdf } from "@boxpdf/html-reader";
const pdf = await PDFDocument.create();
const inter = await loadFont(pdf, await readFile("Inter-Regular.ttf"));
const interBold = await loadFont(pdf, await readFile("Inter-Bold.ttf"));
const logo = await loadImage(pdf, await readFile("logo.png"));
const bytes = await htmlToPdf(await readFile("invoice.html", "utf8"), {
pdf, // reuse the document you embedded into
font: inter,
boldFont: interBold,
resolveImage: ({ url }) => (url === "logo.png" ? logo : undefined),
margin: 40
});
选项:font / boldFont / italicFont / boldItalicFont(默认使用 Helvetica)、pdf(渲染到现有文档中)、margin(默认值为 40)、size(默认值为 US Letter)、width(CSS 包含块宽度;默认为页面内容宽度)、debug,以及 htmlToBoxpdf 接受的所有选项(resolveFont、resolveImage、baseUrl、defaultFontSize、defaultColor、diagnostics、profile)。
htmlToBoxpdf — 节点,用于全面控制
htmlToBoxpdf 无需渲染即可将 HTML 转换为普通的 boxpdf 节点。当你需要节点本身、warnings/diagnostics、多次渲染,或 renderFlow 页眉/页脚时,可使用它。
import { readFile } from "node:fs/promises";
import { PDFDocument } from "pdf-lib";
import { loadFont, loadImage, renderFlow } from "@boxpdf/writer";
import { fontFamily, htmlToBoxpdf } from "@boxpdf/html-reader";
const html = await readFile("invoice.html", "utf8");
const pdf = await PDFDocument.create();
const inter = await loadFont(pdf, await readFile("Inter-Regular.ttf"));
const interBold = await loadFont(pdf, await readFile("Inter-Bold.ttf"));
const logo = await loadImage(pdf, await readFile("logo.png"));
const result = htmlToBoxpdf(html, {
font: inter,
boldFont: interBold,
resolveFont: fontFamily({
Inter: { normal: inter, bold: interBold },
"sans-serif": { normal: inter, bold: interBold }
}),
resolveImage: ({ url }) => (url === "logo.png" ? logo : undefined),
baseUrl: process.cwd(),
width: 532
});
console.log(result.warnings);
await renderFlow(pdf, result.nodes, { margin: 40 });
const bytes = await pdf.save();
width 是以 PDF 点为单位的 CSS 包含块宽度。带有 40pt 页边距的 US Letter 页面,其内容宽度为 532pt,因此 width: 532 是不错的默认值。
streamHtmlToPdf — 有界的大文档转换
streamHtmlToPdf 接受一个函数,在两次处理时重新打开 HTML,并以增量方式写入 PDF 字节。调用前嵌入字体;使用 prepare 在输出开始前嵌入资源预检发现的图像。
import { createReadStream, createWriteStream } from "node:fs";
import { PDFDocument, StandardFonts } from "pdf-lib";
import { nodeAdapter } from "@boxpdf/writer";
import { streamHtmlToPdf } from "@boxpdf/html-reader";
const pdf = await PDFDocument.create();
const font = await pdf.embedFont(StandardFonts.Helvetica);
const result = await streamHtmlToPdf(
() => createReadStream("archive.html"),
nodeAdapter(createWriteStream("archive.pdf")),
{ pdf, font, width: 532, margin: 40 }
);
console.log(result.pageCount, result.dom.maxBufferedNodes);
普通块级包装器和表格会以有界的续接片段释放。flex/grid、定位或变换容器,以及单个连续不断的文本节点等原子布局都有明确的安全上限;如果无法安全流式处理,就会报出有用的错误。含义取决于同级元素位置的选择器会保守地禁用包装器分片。
字体
字体需显式指定。boxpdf-html 不会发现系统字体,也不附带浏览器字体栈。这样可以确保渲染结果稳定,并适用于无服务器运行环境。
至少要传入 font。如果 HTML 使用粗体或斜体文本,还要传入 boldFont 和 italicFont:
const result = htmlToBoxpdf(html, {
font,
boldFont,
italicFont,
width: 532
});
对于 CSS font-family,请使用 fontFamily():
const resolveFont = fontFamily({
Inter: {
normal: interRegular,
bold: interBold,
italic: interItalic,
boldItalic: interBoldItalic
},
Helvetica: {
normal: fallback,
bold: fallbackBold
},
"sans-serif": {
normal: fallback,
bold: fallbackBold
}
});
解析器会接收 { families, weight, style },并返回 pdf-lib PDFFont。如果需要更宽松的映射、字体别名、特定语言的回退字体或字重合成,可以提供自己的解析器。
注意事项:
font-family: system-ui只有在解析器映射了system-ui时才有效。- pdf-lib 标准字体使用方便,但有诸多限制;实际文档请使用嵌入的 TTF/OTF 字体。
- 复杂字形塑形取决于 pdf-lib/fontkit 的行为。目标场景是西方语言的发票/报告文本。
- 字体度量会影响布局。需要确保视觉效果稳定时,请在测试和生产环境中使用相同的嵌入字体。
Tailwind CSS
只有在渲染 Tailwind 生成的 CSS 时,Tailwind 才能正常工作;仅有原始类名是不够的。常见流程如下:
- 使用 Tailwind 类编写文档 HTML。
- 针对该 HTML 运行 Tailwind。
- 将生成的 CSS 内联,或传给
boxpdf-html。 - 使用与预期 PDF 内容区域相匹配的包含宽度进行渲染。
示例源代码:
<div class="p-6 bg-[#f8fafc] text-gray-900">
<div class="max-w-[520px] rounded-[10px] border bg-white p-5 shadow-sm">
<div class="grid grid-cols-[1fr_2fr] gap-x-4 gap-y-3">
<div class="rounded-md border border-blue-200 bg-blue-50 p-3">
<p class="text-xs font-semibold uppercase tracking-wide text-blue-700">Status</p>
<p class="mt-1 text-sm font-bold">Paid</p>
</div>
<div class="rounded-md border border-gray-200 p-3">
<p class="text-xs font-semibold uppercase tracking-wide text-gray-600">Notes</p>
<p class="mt-1 text-sm leading-5">Two fraction column wraps later.</p>
</div>
</div>
</div>
</div>
构建 CSS:
@import "tailwindcss";
@source "./invoice.html";
npx tailwindcss -i ./tailwind-input.css -o ./tailwind-output.css --minify
npx @boxpdf/html-reader invoice.html invoice.pdf --css ./tailwind-output.css
支持的 Tailwind 模式包括常见的间距、颜色、文本、边框、圆角、宽度/高度、flex、grid、表格、图像和任意值工具类。可使用 --unsupported-css 或 diagnostics: { unsupportedCss: true } 报告不支持的工具类声明。
Tailwind 注意事项:
- 响应式/状态变体会按 CSS 解析;不会与视口交互。请为所需的 PDF 选择一套生成的 CSS。
- 二维变换支持按顺序排列的
translate、scale、rotate、skew和matrix函数列表、对应的 X/Y 变体、transform-origin,以及独立的translate、rotate和scale属性。支持长度/百分比平移以及deg、grad、rad和turn角度。忽略或报告不支持三维变换、阴影、滤镜、过渡效果和仅限浏览器的效果。 - Tailwind preflight 重置大多不会造成问题。诊断有意侧重于工具类选择器,而不是容易产生噪声的基础选择器。
- 如果文本布局很重要,请在 Tailwind 设计审查和 PDF 渲染中使用相同的字体。
图像
由于 pdf-lib 图像必须在渲染前嵌入,因此 API 使用 resolveImage:
const images = new Map([
["logo.png", await loadImage(pdf, await readFile("logo.png"))]
]);
htmlToBoxpdf(html, {
font,
resolveImage: ({ url }) => images.get(url),
baseUrl: process.cwd()
});
CLI 会预加载 <img src> 和 CSS url(...) 引用的本地、http(s) 及 data: 图像 URL。对于缺失的图像,如果能推断出宽度/高度,就会保留其布局框。
CSS 和 HTML 支持范围
支持:
- 通过
parse5解析 HTML 片段和完整文档。 - 通过
css-tree解析样式表和内联样式。 - 选择器:标签、类、id、属性、后代、子级/兄弟组合符、常见结构伪类,以及转义后的 Tailwind 选择器。
- 级联基础:样式表规则、内联样式、
!important、继承、自定义属性、var()和常见的calc()。 - 布局:block、inline、inline-block、inline-flex、inline-grid、flex、grid 回退、表格、浮动、绝对/相对定位、z-index、隐藏溢出和替换图像。
- 文本:富内联文本段、硬换行、普通/不换行/类似 pre 的空白、文本转换、装饰、对齐、垂直对齐、列表悬挂缩进和换行。
- 尺寸/样式:CSS px 到点的转换、pt、em/rem、vw/vh、常见场景中的百分比、最小/最大宽度、box-sizing、外边距/内边距/间距、背景、背景图像、边框、单侧边框、边框折叠、圆角、object-fit。
不是浏览器:
- 不执行 JavaScript。
- 不支持交互或动态布局。
- 不支持完整的浏览器绘制模型。
- 不发现系统字体。
- CSS 支持有意针对静态文档输出进行了扩展。使用诊断信息查找实际模板中不受支持的声明。
诊断
const result = htmlToBoxpdf(html, {
font,
width: 532,
diagnostics: { unsupportedCss: true, sampleLimit: 3 },
profile: (event) => console.log(event.phase, event.elapsedMs)
});
console.log(result.diagnostics?.unsupportedCss);
不受支持的 CSS 诊断信息会按属性/值对汇总,并包含选择器示例。性能分析事件涵盖解析、CSS、样式计算、渲染树构建和输出节点计数。
实用命令:
pnpm run typecheck
pnpm run test
pnpm run build
pnpm run tailwind:fixture
pnpm run visual:check
pnpm run pack:release
BOXPDF_DEP_VERSION=^1.7.0 pnpm run publish:release
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。