使用 pdf-lib 库在 TypeScript 中生成 PDF 报告
在现代 Web 开发中,经常需要创建 PDF 格式的文档——从简单的收据和凭证到带有图表的复杂分析报告。TypeScript 作为 JavaScript 的强类型扩展,为处理 PDF 提供了出色的能力。在众多库中,pdf-lib 脱颖而出——它是一个功能强大、完全客户端的工具,无需服务器端依赖。
在本文中,我们将详细介绍如何使用 pdf-lib 在 TypeScript 中生成 PDF 报告,包括安装、基本操作和高级技巧。
什么是 pdf-lib?
pdf-lib 是一个用 TypeScript 编写的开源库,允许直接在浏览器或 Node.js 环境中创建和编辑 PDF 文档。其主要优势包括:
- 完全支持 TypeScript(包含所有类型定义)
- 无需外部依赖(无需 Puppeteer 或 wkhtmltopdf)
- 支持处理现有 PDF(合并、插入页面)
- 支持西里尔字母和任何字体
- 嵌入图像(PNG、JPG、SVG)
- 创建表单和注释
安装与配置
使用标准包管理器进行安装:
npm install pdf-lib# 或yarn add pdf-lib使用 TypeScript 无需额外操作——所有类型已包含在包中。
基础示例:创建简单报告
我们来看一个创建包含标题和文本的最小 PDF 文档的示例:
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
async function createSimpleReport() { // 1. 创建新的 PDF 文档 const pdfDoc = await PDFDocument.create(); // 2. 添加页面(A4 格式:595.28 x 841.89 点) const page = pdfDoc.addPage([595.28, 841.89]); // 3. 嵌入标准字体 const font = await pdfDoc.embedFont(StandardFonts.Helvetica); // 4. 绘制标题 page.drawText('2025 年第一季度销售报告', { x: 50, y: 800, size: 24, font: font, color: rgb(0, 0.2, 0.6), }); // 5. 绘制正文 page.drawText('总收入:1,234,567 卢布', { x: 50, y: 760, size: 14, font: font, color: rgb(0, 0, 0), }); // 6. 将文档保存为 Uint8Array const pdfBytes = await pdfDoc.save(); return pdfBytes;}处理表格和数据
要创建表格报告,需要稍微多一些逻辑。以下是一个生成数据表格的示例:
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
interface SaleRecord { product: string; quantity: number; price: number;}
async function createTableReport(data: SaleRecord[]) { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage([595.28, 841.89]); const font = await pdfDoc.embedFont(StandardFonts.Helvetica); const boldFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold); const startX = 50; let startY = 800; const rowHeight = 25; const colWidths = [200, 100, 100, 100]; // 名称, 数量, 单价, 金额 // 表格标题 const headers = ['名称', '数量', '单价', '金额']; page.drawText(headers[0], { x: startX, y: startY, size: 12, font: boldFont }); page.drawText(headers[1], { x: startX + colWidths[0], y: startY, size: 12, font: boldFont }); page.drawText(headers[2], { x: startX + colWidths[0] + colWidths[1], y: startY, size: 12, font: boldFont }); page.drawText(headers[3], { x: startX + colWidths[0] + colWidths[1] + colWidths[2], y: startY, size: 12, font: boldFont }); startY -= rowHeight; // 数据行 for (const record of data) { const total = reco