jsPDF 很适合轻量浏览器导出
jsPDF 流行是因为它解决了真实产品问题:不运行后端服务,也能在浏览器内创建 PDF。开发者可以绘制文字、线条、图片和简单表格,然后在同一页面触发下载。对原型、小型管理界面、本地收据和离线 PWA 来说,这是很强的适配。
产品问题在于:这个浏览器边界什么时候不再合适。当 PDF 变成客户要扫描、归档、邮件发送或提交到另一个系统的业务文档时,工作就不再只是“画一个文件”。它会变成字体管理、条码精度、移动端稳定性、确定性输出,有时还包括 PDF/A 或电子发票打包。
同样输出 PDF,不同的产品边界
使用 jsPDF 时,你的前端应用就是渲染器。每个浏览器标签页都要持有库、任何自定义字体、中间图片、条码输出和最终 PDF 字节。库账单为零,但生产责任转移到每台用户设备上。
使用 gPdf 时,浏览器或后端发送结构化的 DocumentRequest 或 template_id + data 请求。gPdf 在 Edge 侧拥有渲染环境、内置字体、条码几何和二进制 PDF 生成。应用仍然负责数据和模板逻辑,而不是 PDF 引擎。
产品适配:离线导出 vs 运营文档
当 PDF 只是本地便利功能时,选择 jsPDF:一个小导出按钮、简单的纯拉丁文字收据、仪表盘快照,或必须在无网络时继续工作的 PWA。
当 PDF 是运营流程的一部分时,选择 gPdf:物流面单、仓库标签、发票、票券、对账单、报关表、跨境收据。这些文档需要跨设备保持一致输出,而不是依赖当前浏览器标签页安全组装的结果。
成本模型:免费库 vs 自有生产面
jsPDF 库有明显价格优势:库本身开源,浏览器 CPU 不会出现在你的云账单上。对小型内部功能来说,这可能是最低成本路径。
生产成本出现在库的周围:
- CJK 字体文件或生成的 base64 字体模块。
- 条码编码和转换库。
- 浏览器特定的内存和下载问题。
- 扫码器和热敏打印机的打印质量检查。
- 跨桌面、iOS Safari、Android WebView 和嵌入式浏览器的回归测试。
gPdf 把这些变成使用量账单。公开 Basic 方案从 5 美元/月、10 万页开始,标准超量从每页 0.00005 美元起。这是供应商成本,但它移除了让每个前端包和每台用户设备都像生产 PDF 服务一样工作的需要。
CJK 成本不只是文件大小
第一个硬边界是 CJK 文本:中文、日文和韩文。
jsPDF 的内置标准 PDF 字体适合简单拉丁文字输出,但不覆盖所有 Unicode 字形。当文档包含 CJK 文本时,应用需要实际包含这些字形的字体。实践中,浏览器端实现通常会打包 TTF 文件、把它转换成 base64 JavaScript 模块,或在生成 PDF 前获取字体数据。
这份成本会付两次:首先是更大的前端载荷,然后是 PDF 生成时更多的浏览器内存。在移动端,同一个标签页可能同时持有 Web 应用、字体、条码缓冲区、图片和最终 PDF 字节。
gPdf 把这项工作留在服务端。浏览器发送结构化 JSON;渲染器从内置字体中选择,覆盖拉丁、希腊、西里尔、CJK、阿拉伯、天城文、孟加拉、泰文和等宽文本。一个 2 KB 的订单载荷,不应该变成 12 MB 的字体分发路径。
条码成本:编码容易,打印可靠性更难
对物流、电商、制造、医疗、票务和零售流程来说,条码有时比可见文字更重要。人读订单号,业务读 Code 128、GS1-128、QR、DataMatrix 或 PDF417。
使用 jsPDF 时,条码生成通常是另一个产品决策。团队把 jsPDF 和另一个编码器组合起来,把条码渲染成 SVG、Canvas 或图片,再放进 PDF。这对优惠券二维码或概念验证是可行的。
当打印条码在运营上很关键时,它会变得脆弱:
- Canvas 条码可能被错误分辨率栅格化。
- 缩放后的图片可能模糊条、模块或静区。
- 浏览器、CSS transform 或导出路径可能改变最终物理尺寸。
- 不同条码格式可能需要不同库或转换路径。
- 203 DPI 热敏打印机会很快暴露小尺寸错误。
gPdf 把条码当成文档元素。请求声明 type: "barcode"、format、载荷和毫米单位物理尺寸。对支持的 1D 和 2D 格式,渲染器在 PDF 内输出矢量条码几何,所以文字、形状、表格、图片和条码都在同一个坐标系中。
Studio 和模板迭代
jsPDF 是代码优先。布局变更通常意味着修改 JavaScript 绘图命令、位置、字体注册、图片转换和条码放置。
gPdf 支持同样的 API 优先流程,但增加了 gPdf Studio 作为免费的 PDF 布局可视化设计器。团队可以添加并拖拽文本、图片、表格、形状、页眉、页脚和条码,然后把设计连接到 template_id + data 生成。当物流面单、发票或收据格式经常变化,且非 PDF 专家也需要参与布局时,这很重要。
移动浏览器不是重 PDF 工作的好地方
客户端 PDF 生成看似便宜,因为服务器账单为零。成本会转移到用户设备上。
桌面端可能没问题。移动浏览器上,生产文档会对标签页施加很大压力:CJK 字体数据、base64 图片、Canvas 缓冲区、条码图片、生成的 PDF 字节和正在运行的应用同时竞争内存。iOS Safari 和低内存 Android 设备没有开发者笔记本那么宽容。
把生成移到 gPdf 会改变问题形态。浏览器构建一个小 JSON 请求,等待二进制响应,然后下载完成的 PDF。用户标签页不再需要同时充当字体管理器、条码渲染器、布局引擎和二进制 PDF 写入器。
什么时候 jsPDF 仍然是正确选择
继续使用 jsPDF 有充分理由。
如果用户必须离线导出,jsPDF 更合适。如果数据完全不能离开设备,浏览器端生成是更干净的隐私边界。如果文档很小、只有拉丁文字、偶尔使用,引入 API 的运营成本可能不值得。对原型和内部工具来说,jsPDF 经常就是最快路径。
当输出成为运营流程的一部分时,决策会改变:必须能扫描的物流面单、必须归档的发票、必须验证的票券、必须正确渲染 CJK 姓名的跨境订单文档。此时,“在浏览器里生成 PDF”不如“可靠生成同一份生产 PDF”重要。
迁移形态
迁移不是“替换一个函数调用”。它是从命令式浏览器绘图,移动到结构化文档请求。
- // Before: browser-side drawing with jsPDF plus extra font/barcode setup.
- import { jsPDF } from "jspdf";
- import JsBarcode from "jsbarcode";
-
- const doc = new jsPDF({ unit: "mm", format: [100, 150] });
- // Load a CJK-capable TTF and register it before drawing CJK text.
- doc.addFileToVFS("NotoSansCJK-Regular.ttf", base64Font);
- doc.addFont("NotoSansCJK-Regular.ttf", "NotoSansCJK", "normal");
- doc.setFont("NotoSansCJK");
- doc.text("跨境订单 / Cross-border order", 6, 10);
-
- // Generate a barcode separately, then place it into the PDF.
- JsBarcode(canvas, "PDN0003507278", { format: "CODE128" });
- doc.addImage(canvas.toDataURL("image/png"), "PNG", 6, 72, 72, 20);
- doc.save("label.pdf");
+
+ // After: send one structured DocumentRequest to gPdf.
+ const res = await fetch("https://api.gpdf.com/api/v1/pdf/render", {
+ method: "POST",
+ headers: {
+ Authorization: `Bearer ${KEY}`,
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({
+ settings: {
+ defaults: {
+ text: {
+ font_family: "NotoSans-Regular",
+ font_mode: "prefer",
+ font_size: 9,
+ color: "#111827"
+ }
+ }
+ },
+ pages: [{
+ width: 100,
+ height: 150,
+ elements: [
+ {
+ type: "text",
+ x: 6,
+ y: 8,
+ content: "跨境订单 / Cross-border order",
+ style: { width: 88, font_size: 12, font_weight: "bold" }
+ },
+ {
+ type: "barcode",
+ x: 6,
+ y: 70,
+ width: 72,
+ height: 18,
+ format: "code128",
+ content: "PDN0003507278",
+ barcode_text: { enabled: true, position: "bottom", offset: 1 }
+ },
+ {
+ type: "barcode",
+ x: 80,
+ y: 8,
+ width: 14,
+ height: 14,
+ format: "qrcode",
+ content: "https://track.example/PDN0003507278",
+ barcode_text: { enabled: false, position: "bottom" }
+ }
+ ]
+ }]
+ })
+ });
+ const pdf = await res.arrayBuffer();
重要转变是所有权。使用 jsPDF 时,你的 Web 应用拥有 CJK 字体路径、条码生成路径、浏览器内存特征和导出行为。使用 gPdf 时,你的应用拥有数据和模板;Edge 渲染器拥有文档机制。
相关 PDF 生成场景
如果你的评估从浏览器内 PDF 导出开始,建议先判断是否必须离线:离线导出和本地专用文档仍然适合 jsPDF;需要稳定输出的生产文档,可以继续看 JSON 转 PDF API、发票 PDF API、物流面单 API、GS1 条码 API 和 模板 PDF API。涉及归档或电子发票时,再看 PDF/A API 与 Factur-X API。
FAQ
jsPDF 免费吗?
库本身是开源的。生产成本在周边工作:CJK 字体、条码库、浏览器质量检查、打印质量检查,以及支持内存不足的设备。
gPdf 会取代所有 jsPDF 用例吗?
不会。离线浏览器导出和本地专用文档仍然是 jsPDF 的天然场景。gPdf 适合那些受控渲染器值得一次 API 调用的生产文档。
为什么单独讨论条码成本?
因为屏幕上看起来没问题的条码,经过缩放、栅格化或热敏打印后仍可能失败。运营文档需要的是扫码可靠性,不只是可见图案。
相关页面
- gPdf API 参考 - DocumentRequest、条码元素、字体回退和渲染端点。
- PDF 中的矢量条码 vs 栅格条码 - 为什么打印后的条码几何很重要。
- JSON 中 0.1 mm 精度的 GS1-128 条码 - 面向标签的条码尺寸细节。
- 面向工程师的 PDF/A 与 Factur-X 解释 - 归档和电子发票要求何时进入 PDF 流程。