mcpField
B
boxpdf-html

boxpdf-html

本地服务
github.com生产力23 周前更新

关于 boxpdf-html

boxpdf-html 使用 boxpdf 库将编写好的 HTML 转为静态 PDF,适用于发票和报告等文档。它还提供 MCP 服务,包含 PDF 渲染工具和库文档指导。

主要功能

  1. 01通过命令行和 API 将 HTML 转为 PDF
  2. 02MCP 转换工具与库使用指导
  3. 03CSS 诊断及不支持样式报告
  4. 04自定义嵌入字体与图像处理
  5. 05大型文档流式转换
  6. 06命令行 PDF 密码加密

适用场景

  1. 01根据发票或收据 HTML 生成 PDF
  2. 02渲染文档使用的 Tailwind CSS
  3. 03增量转换大型 HTML 归档
  4. 04为 Agent 提供 PDF 生成指导

MCP 相关

stdio MCP 服务提供 `html_to_pdf`,可渲染 HTML 和可选 CSS;`boxpdf_docs` 提供针对性的库使用指导。服务还提供指南、README 和模板资源。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"earonesty-boxpdf-html": {
"command": "npx",
"args": [
"-y",
"boxpdf-html"
]
}
}
}
启动命令npx -y boxpdf-html

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmboxpdf-html1.7.0

工具

2

收录的工具列表 · 更新于 2 周前

参数类型必填说明
cssstring否渲染前注入的额外样式表(例如,已编译的 Tailwind 输出)。
htmlstring是HTML 标记。可包含 <style> 块和内联样式。
sizeenum否每页条目数。Letter | Legal | Tabloid | A4 | A5 | A6
debugboolean否绘制 boxpdf 调试叠加层。
fontsobject否可选的 TTF/OTF 文件路径,用于嵌入字体,以替代内置的 Helvetica 字体系列。
fonts.boldstring否
fonts.italicstring否
fonts.regularstring否
fonts.boldItalicstring否
marginnumber否PDF 页面边距,单位为点。
baseUrlstring否用于解析相对 <img> 和 background-image URL 的目录或 URL。默认为工作目录。
outputPathstring否PDF 的写入位置(可使用相对于 cwd 的路径)。如果省略,PDF 将以内联 base64 资源形式返回。
allowRemoteboolean否允许获取 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 才能正常工作;仅有原始类名是不够的。常见流程如下:

  1. 使用 Tailwind 类编写文档 HTML。
  2. 针对该 HTML 运行 Tailwind。
  3. 将生成的 CSS 内联,或传给 boxpdf-html。
  4. 使用与预期 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

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。