jsPDF 中文显示实战指南:addFileToVFS 与 addFont 字体加载全流程
【免费下载链接】jsPDFClient-side JavaScript PDF generation for everyone.项目地址: https://gitcode.com/gh_mirrors/js/jsPDF
jsPDF 是一款在浏览器端生成 PDF 的轻量级库,内置的 14 种 PDF 标准字体只覆盖 ASCII 字符集,所以直接用默认字体写中文常常出现乱码或空白。解决路径并不复杂:把一份包含中文字形(glyph)的 TTF 字体文件加载进文档,再用setFont指定它。本文基于仓库中的真实源码和示例,说明加载方式、字体选择、效果验证和常见坑,适合第一次处理 jsPDF 中文字体的开发者。
什么场景下中文会"失灵"
先定位问题,避免在错误方向上花时间。用默认字体(如helvetica)调用doc.text("中文", 20, 20)时,典型表现有两种:
- 输出乱码字符;
- 汉字位置"缺失",表现为空白或宽度异常。
仓库 README 对此有明确说明:PDF 标准字体受限于 ASCII codepage,想要 UTF-8 文本(比如 Chinese text),必须集成一个自带所需字形的自定义字体,否则就会显示乱码。所以中文显示从来不是"开关",而是三件套的组合:TTF 字体文件 + 加载进文档 + 用 setFont 指定。理解这一点后,后面所有操作都是围绕这三件事展开。
最小落地方式:两步把字体装进文档
核心流程只有两步:先用addFileToVFS把 TTF 文件放进文档的 vFS(virtual file system,虚拟文件系统),再用addFont声明字体。官方 README 推荐的做法如下:
const doc = new jsPDF(); // 用 fetch 把 MyFont.ttf 读成 binary string const myFont = ...; // 字体文件内容 doc.addFileToVFS("MyFont.ttf", myFont); doc.addFont("MyFont.ttf", "MyFont", "normal"); doc.setFont("MyFont");addFont三个参数分别对应:vFS 中的文件名、代码里使用的字体名(可自定义)、字体样式。装好字体后,输出中文就是普通文本调用:
doc.setFontSize(16); doc.text("jsPDF 中文显示实战", 20, 30); doc.save("chinese-demo.pdf");预期效果:打开生成的 PDF,中文正常显示、字距正常。如果仍乱码,问题通常在字体文件本身(见下文),而不是代码顺序。
如果不想自己写 fetch 逻辑,仓库提供了fontconverter/fontconverter.html工具:把本地 TTF 转成 base64 编码的 js 文件,并附带注册代码,引入项目后即可直接调用addFont。仓库示例 examples/js/japanese.js 和 examples/js/arabic.js 正是这种用法——前者加载MouhitsuBold.ttf输出日文,后者加载Amiri-Regular.ttf输出阿拉伯文。这两个示例可以直接当作中文字体加载的模板改写。
怎么选一份合适的中文 TTF 字体文件
字体文件决定了显示效果和最终 PDF 体积,选型时看三点:
- 字形覆盖面:字体必须包含你要输出的汉字。只输出一部分常用字时,选覆盖范围够用的开源字体即可;
test/reference/目录下有若干 TTF 可供测试参考。 - 体积:中文字体普遍在数 MB 量级,而字体最终会被嵌入生成的 PDF,输出文件会比纯英文文档明显更大。文本量小的页面建议做字体子集化(subsetting),只保留实际用到的字符。从 src/modules/ttfsupport.js 可以看到,字体元数据中维护了
glyIdsUsed(已使用字形 ID 列表),这就是输出时做字形裁剪的实现基础。 - 样式配套:需要粗体中文时,要单独准备一份 bold TTF,并用相同字体名、
"bold"样式再注册一次;只注册了 normal 却在代码里setFont(name, "bold"),效果会不符合预期。
验证中文显示效果:三个检查点
生成 PDF 后,建议按三个点确认结果,而不只是"看一眼":
- 完整性:全部汉字显示完整,无乱码、无缺字空白;
- 混排:中英文混排段落中,通过
setFont在默认字体和中文字体间切换,换行与行距没有异常跳变; - 尺寸:
setFontSize以 pt 为单位控制字号,同样字号下全角汉字的视觉宽度约为半角拉丁字符的两倍,这是正常现象,不是 bug。
仓库的测试用例 test/specs/unicode.spec.js 里有"先放 vFS 再注册"的完整写法,可以作为自检脚本的参考:
doc.addFileToVFS("PTSans.ttf", PTSans); doc.addFont("PTSans.ttf", "PTSans", "normal");把字体名换成你的中文字体,模式完全一致。
常见坑位排查:四类报错与现象
结合 src/modules/ttfsupport.js 中addFont事件处理器的逻辑,实际踩坑基本集中在四类:
Font does not exist in vFS:调用了addFont,但对应文件名从未通过addFileToVFS放入 vFS,处理逻辑会直接抛错。检查两个调用的先后顺序与文件名拼写即可。Font is not stored as string-data in vFS:vFS 里放的数据类型不对(比如传入了Uint8Array而非 binary string)。把 TTF 读成二进制字符串,或改用 fontconverter 生成的 base64 文件。- 部分字乱码、部分正常:字体覆盖面不足,该字符的 glyph 根本不在字体文件里。换覆盖面更广的字体,或避开这些字。
- PDF 体积明显变大:属于预期行为,字体被嵌入了文档。缓解手段是字体子集化与 PDF 压缩,而不是删功能。
📌 一个实用技巧:排查时先打印确认addFileToVFS的文件名与addFont第一参数字符串完全一致,绝大多数"字体不存在"的问题出在这个细节上。
备选路径与相关入口
如果你的真实场景是"把一段 HTML 转成 PDF"而非逐行画文本,可以先评估 jsPDF 的 html 模块(src/modules/html.js),示例位于examples/html2pdf/目录。无论走哪条路径,中文字体的注册方式都一致:字体必须在使用前完成加载,setLanguage、splitTextToSize等排版功能对已注册的自定义字体同样生效。
收尾建议:把"字体加载顺序 + 字体覆盖面"做成团队内的检查清单——先确认 TTF 里有目标字符,再按addFileToVFS → addFont → setFont的顺序接入,中文显示问题大多在接入阶段就能定位清楚。
【免费下载链接】jsPDFClient-side JavaScript PDF generation for everyone.项目地址: https://gitcode.com/gh_mirrors/js/jsPDF
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考