pdfkit vs pdf-lib
前端 PDF 文档生成与编辑库选型对比
pdfkitpdf-lib类似的npm包:

前端 PDF 文档生成与编辑库选型对比

pdf-libpdfkit 都是用于在 JavaScript 环境中创建和操作 PDF 文档的流行库,但它们的设计目标、运行环境支持和核心能力存在显著差异。pdf-lib 专注于在浏览器和 Node.js 中读取、修改和写入现有 PDF 文件,支持文本、图像和表单字段的编辑,并原生支持 WebAssembly 以提升性能。pdfkit 则是一个从零开始生成 PDF 的库,采用类似 Canvas 的绘图 API,适合需要完全控制页面布局和内容渲染的场景,但不支持直接修改已有 PDF。两者在前端工程中的适用性取决于具体需求:是否需要编辑现有文档、是否依赖服务端渲染、以及对字体和图形的精细控制程度。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
pdfkit4,617,39210,6728.43 MB3471 个月前MIT
pdf-lib08,541-3175 年前MIT

pdf-lib vs pdfkit:前端 PDF 生成与编辑能力深度对比

在现代 Web 应用中,PDF 操作需求日益普遍 —— 从生成电子发票到在线签署合同。pdf-libpdfkit 是两个主流选择,但它们解决的问题本质不同。本文将从真实开发场景出发,对比两者的核心能力、API 设计和适用边界。

📄 核心定位:编辑现有 PDF vs 从零生成 PDF

pdf-lib 的核心优势在于 读取和修改已有 PDF。它能解析 PDF 结构,让你添加文本、图像、注释,甚至填写表单字段,而保持原始文档的布局不变。

// pdf-lib: 加载现有 PDF 并添加文本
import { PDFDocument, rgb } from 'pdf-lib';
import existingPdfBytes from './template.pdf';

const pdfDoc = await PDFDocument.load(existingPdfBytes);
const pages = pdfDoc.getPages();
const firstPage = pages[0];

firstPage.drawText('已签署', {
  x: 100,
  y: 200,
  size: 24,
  color: rgb(1, 0, 0),
});

const modifiedPdfBytes = await pdfDoc.save();

pdfkit 则专注于 从空白画布生成全新 PDF。它提供类似 Canvas 的 API,让你逐行绘制文本、图形和图像,但无法加载或修改已有 PDF。

// pdfkit: 从零创建 PDF
import PDFDocument from 'pdfkit';
import fs from 'fs';

const doc = new PDFDocument();
doc.pipe(fs.createWriteStream('output.pdf'));

doc.fontSize(25).text('Hello World', 100, 100);
doc.end();

💡 关键区别:如果你有 PDF 模板需要填充(如合同、申请表),pdf-lib 是唯一可行方案;如果要动态生成报表(如销售数据图表),pdfkit 更灵活。

🌐 运行环境:浏览器优先 vs 服务端优先

pdf-lib 被设计为 真正的跨平台库。它在浏览器和 Node.js 中行为一致,无需额外配置即可在 React/Vue 应用中直接使用,且所有操作都在客户端完成,避免隐私敏感数据上传服务器。

// 在浏览器中直接使用 pdf-lib(无 Node.js 依赖)
const arrayBuffer = await fetch('/template.pdf').then(res => res.arrayBuffer());
const pdfDoc = await PDFDocument.load(arrayBuffer);
// ... 修改后触发下载
const blob = new Blob([await pdfDoc.save()], { type: 'application/pdf' });

pdfkit 虽然理论上可在浏览器中运行,但 实际依赖 Node.js 特性(如 fsstream)。要在前端使用,必须通过 Webpack/Browserify 打包,并手动处理字体文件(通常需转换为 base64 或 ArrayBuffer),增加了复杂度。

// pdfkit 在浏览器中需额外处理字体
import PDFDocument from 'pdfkit';
import fontData from './font.ttf'; // 需预加载为 ArrayBuffer

const doc = new PDFDocument();
doc.registerFont('CustomFont', fontData);
doc.font('CustomFont').text('自定义字体', 100, 100);

⚠️ 注意:pdfkit 的官方文档明确说明其主要面向 Node.js,浏览器支持属于“社区实验性质”,生产环境需谨慎评估。

✍️ 文本与字体处理:开箱即用 vs 手动配置

pdf-lib 内置对 标准 PDF 字体(如 Helvetica、Times-Roman)的支持,可直接使用。若需嵌入自定义字体,需提供字体文件的二进制数据(如 TTF/OTF),但 API 简洁:

// pdf-lib 嵌入自定义字体
const fontBytes = await fetch('/font.ttf').then(res => res.arrayBuffer());
const customFont = await pdfDoc.embedFont(fontBytes);

firstPage.drawText('中文', {
  x: 50,
  y: 150,
  font: customFont,
  size: 16,
});

pdfkit 对字体的控制更底层,但 必须显式注册字体。它支持 TrueType、OpenType 等格式,但浏览器中需自行处理字体加载和 CORS 问题:

// pdfkit 注册字体(Node.js 示例)
doc.font('fonts/SourceHanSansCN-Regular.otf')
   .fontSize(16)
   .text('中文', 100, 100);

📌 实践建议:若需大量中文或特殊字体,pdf-lib 的嵌入流程更直观;pdfkit 则适合已知固定字体集的服务端批量生成。

🖼️ 图像与图形支持:基础功能 vs 丰富绘图

pdf-lib 支持插入 JPEG/PNG 图像,但 不支持矢量图形绘制(如路径、贝塞尔曲线)。图像需先转为二进制数据:

// pdf-lib 插入 PNG
const pngImageBytes = await fetch('/logo.png').then(res => res.arrayBuffer());
const pngImage = await pdfDoc.embedPng(pngImageBytes);

firstPage.drawImage(pngImage, {
  x: 200,
  y: 300,
  width: 100,
  height: 50,
});

pdfkit 提供完整的 矢量绘图 API,包括线条、矩形、圆、路径、渐变等,适合生成图表或复杂布局:

// pdfkit 绘制带渐变的矩形
doc.linearGradient(100, 100, 200, 100)
   .color('#FF0000')
   .color('#0000FF')
   .rectangle(100, 100, 100, 50)
   .fill();

💡 场景匹配:若 PDF 内容主要是文本+图片(如证书、报告),pdf-lib 足够;若需动态生成图表、流程图,pdfkit 不可替代。

🔒 表单与交互:唯一选择 vs 不支持

pdf-lib目前唯一支持 PDF 表单操作的主流库。你可以获取表单字段、设置值、甚至扁平化(锁定)表单:

// pdf-lib 填写表单
const form = pdfDoc.getForm();
const nameField = form.getTextField('name');
nameField.setText('张三');

// 锁定表单防止后续编辑
form.flatten();

pdfkit 完全不支持表单。它生成的 PDF 是静态内容,无法包含可交互字段。

🚨 重要结论:任何涉及 PDF 表单(如在线申请、电子签名)的场景,必须选择 pdf-lib

📦 依赖与打包:零依赖 vs 多依赖

pdf-lib 作为纯 ESM/CJS 模块,无外部依赖,可直接通过 CDN 引入或在现代构建工具中 tree-shaking。

pdfkit 依赖多个 Node.js 模块(如 png-js, fontkit),在浏览器中使用时需完整打包,导致 体积显著增大,且可能引入兼容性问题。

🔄 相似之处:共同的基础能力

尽管定位不同,两者在以下方面有交集:

1. 📄 基础文本输出

两者都能输出多行文本、设置字体大小和颜色。

// pdf-lib
page.drawText('文本', { x: 50, y: 500, size: 12 });

// pdfkit
doc.text('文本', 50, 500, { fontSize: 12 });

2. 🖼️ 图像嵌入

均支持嵌入位图(JPEG/PNG),但需预处理为二进制数据。

3. 💾 输出为 ArrayBuffer/Blob

最终都可导出为二进制数据,便于前端下载或上传。

// pdf-lib
const uint8Array = await pdfDoc.save();

// pdfkit (需配合 blob-stream)
const stream = doc.pipe(blobStream());
stream.on('finish', () => {
  const blob = stream.toBlob('application/pdf');
});

📊 总结:关键差异速查表

能力pdf-libpdfkit
编辑现有 PDF✅ 完整支持❌ 不支持
从零生成 PDF✅(但布局控制弱)✅(精细绘图 API)
浏览器原生支持✅ 无需额外配置⚠️ 需打包 + 手动处理字体
PDF 表单操作✅ 填写/扁平化❌ 不支持
矢量图形绘制❌ 仅支持位图✅ 路径/渐变/形状
中文/自定义字体✅ 嵌入简单✅ 但需显式注册
典型场景合同签署、证书生成、表单填充发票、报表、数据可视化 PDF

💡 最终建议

  • pdf-lib:当你需要处理用户上传的 PDF 模板、实现电子签名、或在纯前端完成文档编辑。它是现代 Web 应用中 PDF 交互的首选。
  • pdfkit:当你在服务端生成高度定制化的 PDF(如财务报告、科学图表),且不需要修改已有文档。它在 Node.js 环境中表现卓越,但前端集成成本高。

🌟 记住:两者并非互斥。某些复杂系统会同时使用 —— 用 pdfkit 生成基础报告,再用 pdf-lib 添加数字签名或水印。

如何选择: pdfkit vs pdf-lib

  • pdfkit:

    选择 pdfkit 如果你从零开始生成高度定制化的 PDF 报告、发票或图表,且需要精细控制文本排版、矢量图形和字体嵌入。它更适合服务端渲染或构建时生成静态 PDF,但在浏览器中使用需额外处理字体和依赖,且无法直接编辑已有 PDF。

  • pdf-lib:

    选择 pdf-lib 如果你需要在浏览器或 Node.js 中加载并修改现有的 PDF 文件(例如填写表单、添加水印、合并页面),或者你的应用场景要求跨平台一致的行为(如电子签名、文档批注)。它对现代前端框架(如 React、Vue)友好,且无需额外依赖即可在纯客户端运行。

pdfkit的README

PDFKit

A JavaScript PDF generation library for Node and the browser.

Description

PDFKit is a PDF document generation library for Node and the browser that makes creating complex, multi-page, printable documents easy. The API embraces chainability, and includes both low level functions as well as abstractions for higher level functionality. The PDFKit API is designed to be simple, so generating complex documents is often as simple as a few function calls.

Check out some of the documentation and examples to see for yourself! You can also read the guide as a self-generated PDF with example output displayed inline. If you'd like to see how it was generated, check out the README in the docs folder.

You can also try out an interactive in-browser demo of PDFKit here.

Installation

Use npm or yarn package manager. Just type the following command:

# with npm
npm install pdfkit

# with yarn
yarn add pdfkit

Features

  • Vector graphics
    • HTML5 canvas-like API
    • Path operations
    • SVG path parser for easy path creation
    • Transformations
    • Linear and radial gradients
  • Text
    • Line wrapping (with soft hyphen recognition)
    • Text alignments
    • Bulleted lists
  • Font embedding
    • Supports TrueType (.ttf), OpenType (.otf), WOFF, WOFF2, TrueType Collections (.ttc), and Datafork TrueType (.dfont) fonts
    • Font subsetting
    • See fontkit for more details on advanced glyph layout support.
  • Image embedding
    • Supports JPEG and PNG files (including indexed PNGs, and PNGs with transparency)
  • Tables
  • Annotations
    • Links
    • Notes
    • Highlights
    • Underlines
    • etc.
  • AcroForms
  • Outlines
  • PDF security
    • Encryption
    • Access privileges (printing, copying, modifying, annotating, form filling, content accessibility, document assembly)
  • Accessibility support (marked content, logical structure, Tagged PDF, PDF/UA)

Coming soon!

  • Patterns fills
  • Higher level APIs for laying out content
  • More performance optimizations
  • Even more awesomeness, perhaps written by you! Please fork this repository and send me pull requests.

Example

const PDFDocument = require('pdfkit');
const fs = require('fs');

// Create a document
const doc = new PDFDocument();

// Pipe its output somewhere, like to a file or HTTP response
// See below for browser usage
doc.pipe(fs.createWriteStream('output.pdf'));

// Embed a font, set the font size, and render some text
doc
  .font('fonts/PalatinoBold.ttf')
  .fontSize(25)
  .text('Some text with an embedded font!', 100, 100);

// Add an image, constrain it to a given size, and center it vertically and horizontally
doc.image('path/to/image.png', {
  fit: [250, 300],
  align: 'center',
  valign: 'center'
});

// Add another page
doc
  .addPage()
  .fontSize(25)
  .text('Here is some vector graphics...', 100, 100);

// Draw a triangle
doc
  .save()
  .moveTo(100, 150)
  .lineTo(100, 250)
  .lineTo(200, 250)
  .fill('#FF3300');

// Apply some transforms and render an SVG path with the 'even-odd' fill rule
doc
  .scale(0.6)
  .translate(470, -380)
  .path('M 250,75 L 323,301 131,161 369,161 177,301 z')
  .fill('red', 'even-odd')
  .restore();

// Add some text with annotations
doc
  .addPage()
  .fillColor('blue')
  .text('Here is a link!', 100, 100)
  .underline(100, 100, 160, 27, { color: '#0000FF' })
  .link(100, 100, 160, 27, 'http://google.com/');

// Finalize PDF file
doc.end();

The PDF output from this example (with a few additions) shows the power of PDFKit — producing complex documents with a very small amount of code. For more, see the demo folder and the PDFKit programming guide.

Browser Usage

There are three ways to use PDFKit in the browser:

In addition to PDFKit, you'll need somewhere to stream the output to. HTML5 has a Blob object which can be used to store binary data, and get URLs to this data in order to display PDF output inside an iframe, or upload to a server, etc. In order to get a Blob from the output of PDFKit, you can use the blob-stream module.

The following example uses Browserify or webpack to load PDFKit and blob-stream. See here and here for examples of prebuilt version usage.

// require dependencies
const PDFDocument = require('pdfkit');
const blobStream = require('blob-stream');

// create a document the same way as above
const doc = new PDFDocument();

// pipe the document to a blob
const stream = doc.pipe(blobStream());

// add your content to the document here, as usual

// get a blob when you are done
doc.end();
stream.on('finish', function() {
  // get a blob you can do whatever you like with
  const blob = stream.toBlob('application/pdf');

  // or get a blob URL for display in the browser
  const url = stream.toBlobURL('application/pdf');
  iframe.src = url;
});

You can see an interactive in-browser demo of PDFKit here.

Note that in order to Browserify a project using PDFKit, you need to install the brfs module, which is used to load built-in font data into the package. It is listed as a devDependency in PDFKit's package.json, so it isn't installed by default for Node users. If you forget to install it, Browserify will print an error message.

Documentation

For complete API documentation and more examples, see the PDFKit website.

License

PDFKit is available under the MIT license.