@sv-print/plugin-api-pdf-vector
v0.1.0
Published
add vector pdf api to print template
Maintainers
Readme
@sv-print/plugin-api-pdf-vector
给 sv-print 提供导出矢量 PDF 的 API 插件。
基于 html2realpdf(Zig + WebAssembly 实现),导出的 PDF:
- 文字可选中、可搜索、可复制(含 Unicode 映射,LLM/工具可直接读取文本,无需 OCR)
- 字体子集嵌入(内置 Noto Sans 拉丁字体 + 阿拉伯/希伯来回退,支持注册自定义 TTF 中文字体)
- 原生矢量图形: 边框、背景、渐变、阴影、表格、支持范围内的 SVG 均为矢量绘制
- 链接保留:
http/https/mailto/tel/ftp链接转成 PDF 注释
与 plugin-api-pdf(snapdom 截图 + jsPDF 拼图方案) 相比,不存在像素化、放大模糊的问题,文字密集型文档体积通常更小。
与 plugin-api-pdf 的对比
| | plugin-api-pdf | plugin-api-pdf-vector | | -------- | ------------------------------- | -------------------------------------- | | 渲染方式 | 每页 DOM 截图为 JPEG 再嵌入 PDF | 浏览器快照 → WASM 矢量排版 | | 文字 | 不可选中(图片) | 可选中/可搜索/可复制 | | 体积 | 较大(整页 JPEG) | 较小(矢量 + 字体子集) | | 清晰度 | 受 pixelRatio/quality 限制 | 无限放大不失真 | | 图片资源 | 需同源/可跨域加载 | 需同源/可跨域加载(或 resourceResolver) | | 兼容性 | 纯 JS | 需支持 WebAssembly 的浏览器 |
参数命名与 plugin-api-pdf 保持一致(name/isDownload/type/onProgress 等),调用方法为 toVectorPdf(printData, options)。
安装
npm install @sv-print/plugin-api-pdf-vector @imggion/html2realpdfimport pluginApiPdfVector from "@sv-print/plugin-api-pdf-vector";
const plugins = [pluginApiPdfVector({})];注意: 底层依赖
@imggion/html2realpdf需一并安装(peerDependency)。 其 Worker 与 WASM 资源通过包内相对路径加载,使用 Vite/Webpack 等现代打包器时通常零配置可用。
Vite 开发服务器(dev)注意事项
Vite 的依赖预构建(esbuild)会丢失包内 new URL('./worker.js', import.meta.url) 等资源引用,导致 dev 模式下报 PDF Worker initialization failed。解决办法(二选一):
// vite.config.ts
export default defineConfig({
optimizeDeps: {
// 方案一(推荐): 排除预构建, 让 Vite 按源码处理并正确重写资源路径
exclude: ["@imggion/html2realpdf"],
},
});// 方案二: 插件已内置降级 —— Worker 初始化失败时自动回退 main 线程渲染(控制台会有 warn 提示)
// 也可显式指定:
hiprintTemplate.toVectorPdf(printData, { execution: "main" });生产构建(vite build)不受影响,Rollup 会正确处理资源引用。
示例
let hiprintTemplate = new hiprint.PrintTemplate(options);
// 其中 "text" 是一个元素的 "字段名(field)"
let printData = { text: "这是打印时显示的文本" };
// 1. 直接下载
await hiprintTemplate.toVectorPdf(printData, { name: "pdf名称" });
// 2. 获取 blob 自行处理
const res = await hiprintTemplate.toVectorPdf(printData, {
name: "pdf名称",
isDownload: false, // 不自动下载
type: "blob", // 默认 blob; 支持: blob、arraybuffer、bloburl、datauristring
onProgress: (cur, total, phase) => {
// phase: "snapshot" | "wasm" | "complete" 三阶段
console.log("toVectorPdf 进度", phase, cur, total);
},
});
console.log("toVectorPdf", res); // Blob注册中文字体(含中文内容时必需)
html2realpdf 内置字体仅覆盖拉丁(Noto Sans)+ 阿拉伯/希伯来文,中文等 CJK 字符必须注册 TTF 字体,否则导出报 MissingGlyph 错误:
const fontData = await (await fetch("/fonts/SourceHanSansCN-Regular.ttf")).arrayBuffer();
const res = await hiprintTemplate.toVectorPdf(printData, {
name: "中文名称.pdf",
fonts: [{ family: "SourceHanSansCN", data: fontData }],
});- 注册字体会自动追加为整个模板的
font-family兜底:元素自身字体优先,未覆盖的字符(如中文)回落到注册字体,无需修改模板 - 可同时注册多个字体(如宋体 + 黑体);同一 family 注册不同
weight/style可实现粗体/斜体 - 字体文件需为可嵌入的 TrueType(.ttf),otf/woff 不支持
data支持直接传ArrayBuffer,也支持async () => ArrayBuffer异步函数(首次导出时自动加载,适合按需拉取字体文件)
也可在插件初始化时全局注册:
pluginApiPdfVector({ fonts: [...] })。
toVectorPdf 参数
hiprintTemplate.toVectorPdf(printData, options?)printData: 打印数据(对象或数组)options: 参数对象ToPdfVectorOptions(name/isDownload/type/...)
常用参数(与 plugin-api-pdf 兼容)
| 参数 | 类型 | 默认 | 说明 |
| ---------------------------- | ---------- | ----------------------- | ----------------------------------------------------------- |
| name | string | "sv-print-时间戳.pdf" | 文件名(自动补 .pdf) |
| isDownload | boolean | true | 是否自动下载 |
| type | string | "blob" | 输出类型: blob、arraybuffer、bloburl、datauristring |
| onProgress | function | - | 进度回调 (cur, total, phase) |
| paperWidth / paperHeight | number | 面板尺寸 | 纸张尺寸覆盖(mm) |
| orientation | string | 自动 | "portrait" / "landscape"(传入 paperWidth/Height 时无效) |
矢量渲染相关参数
| 参数 | 类型 | 默认 | 说明 |
| ------------------ | -------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------- |
| fonts | FontRegistration[] | - | 注册嵌入 TTF 字体(含中文内容时必需, 见上文) |
| metadata | object | - | PDF 元数据 { title, author, subject, keywords, creator } |
| enableLinks | boolean | true | 是否保留链接注释 |
| canvasToSvg | function | - | canvas 图表转矢量回调(见下文) |
| fallback | string | "rasterize-subtree" | 不支持的 SVG(如 <use> 引用)策略; 设 "error" 则默认不做 SVG 转图片, 严格保留矢量并按错误中断导出(特殊需求) |
| svgToImage | function | - | SVG 转图片回调(见下文) |
| resourcePolicy | string | "error" | 图片加载失败策略: "omit" 忽略并继续 |
| resourceResolver | function | - | 跨域/受保护资源解析器 |
| baseUrl | string | 页面 URL | 相对资源解析基准 |
| execution | string | "worker" | WASM 执行位置: "worker" / "main" |
| wasmUrl | string | 包内路径 | wasm 资源地址覆盖(CDN 部署时使用) |
| signal | AbortSignal | - | 中断渲染 |
| debug | boolean | true | 控制台输出渲染诊断信息 |
| data | any | - | 打印数据(与第一参数等效) |
echarts 图表保持矢量
echarts 元素默认以 SVG renderer 输出(plugin-ele-echarts 使用 renderer: "svg"),天然矢量。若使用 canvas renderer,可通过 canvasToSvg 让图表库导出 SVG:
const res = await hiprintTemplate.toVectorPdf(printData, {
name: "图表.pdf",
canvasToSvg: (canvas) => {
const chart = echarts.getInstanceByDom(canvas);
return chart ? chart.renderToSVGString() : null;
},
});SVG 默认转图片 / svgToImage 回调
导出时模板内的所有内联 <svg> 默认会转为图片(canvas 栅格化为 PNG), 彻底避开底层 WASM 解析器不支持的特性(<use> 引用、渐变 stroke、非法 preserveAspectRatio 等)导致的 InvalidSvg 中断。
如需自定义处理(服务端渲染、图表库导出、替换品牌图、高清位图等), 通过 svgToImage 回调自行接管:
const res = await hiprintTemplate.toVectorPdf(printData, {
name: "条码.pdf",
// 每个 <svg> 调用一次; 返回图片源, 返回 null 回落默认栅格化
svgToImage: async (svg, { width, height, viewBox }) => {
// 示例: 交给服务端渲染成 PNG
const png = await serverRender(svg.outerHTML);
return png; // 支持 data URL / URL / Blob / <canvas> / <img>
},
});svgToImage返回null→ 走默认 canvas 栅格化svgToImage抛错 → 错误原样透传给toVectorPdf(Promise reject)- 传
fallback: "error"时默认不做 SVG 转图片与栅格化兜底, 完全保留矢量并严格报错(特殊需求) - 除
svgToImage外,canvasToSvg仅用于canvas元素(echarts canvas renderer 等), 二者互不影响
插件初始化配置
pluginApiPdfVector({
execution: "worker", // 默认; Worker 不可用环境可设为 "main"
wasmUrl: "https://cdn.example.com/libhtml2realpdf.wasm", // CDN 部署时覆盖
fonts: [{ family: "SourceHanSansCN", data: fontBuffer }], // 全局注册字体
});注意事项
- 中文字体: 内置字体不含 CJK 字形,未注册中文字体时导出直接报
MissingGlyph错误,请务必通过fonts注册(见上文) - 跨域图片: 图片资源需允许跨域(CORS),否则渲染报错;可用
resourcePolicy: "omit"跳过失败图片或resourceResolver自行解析 - CSS 兼容: 底层渲染引擎有自己的 CSS 支持矩阵(见 css-support.md),自定义
expandCss中使用不支持的属性时会产生诊断信息(debug: true输出) - SVG 兼容: 模板内的内联
<svg>默认转为图片(canvas 栅格化为 PNG),因此<use>引用、渐变 stroke、非法preserveAspectRatio等不支持特性不再中断导出。需要矢量/自定义处理时用svgToImage回调;<img src="*.svg">、CSS 背景 SVG 等仍交由底层处理(不支持的子树自动栅格化)。默认全自动处理,特殊需求才需自行传参(如fallback: "error"严格全矢量、canvasToSvg处理 echarts canvas) - 水印:
watermarkOptions由面板 CSS 绘制时可正常矢量渲染 - 旧浏览器: 需要浏览器支持 WebAssembly 与 module Worker(所有现代浏览器均支持)
- Vite dev: 需排除
@imggion/html2realpdf的依赖预构建(见上文),否则 Worker 404;插件也会自动降级execution: "main"
License
LGPL
开源使用须知
1.请自觉遵守开源协议,其他用途可联系作者;
2.允许用于个人学习、毕业设计、教学案例、公益事业、商业使用;
3.如果商用必须保留版权信息,请自觉遵守;
4.禁止将本开源的代码和资源进行任何形式任何名义的出售,否则产生的一切任何后果责任由侵权者自负;
5.商用请仔细审查代码和漏洞,不得用于任一国家许可范围之外的商业应用,产生的一切任何后果责任自负;
