“PDF 压缩一下” 这件事在搜索结果里有 100 种答案,但每种答案都只对了一半。真相是:PDF 的可压缩空间和它的”内容类型”强相关,一个 5 MB 的扫描件 PDF 可能压到 800 KB,同样 5 MB 的纯文字 PDF 可能只压到 4.7 MB。
本文用 4 种典型 PDF 类型的真实压缩数据,讲清楚:PDF 文件到底由什么组成、各部分的可压缩空间有多大、以及为什么浏览器里跑的本地压缩永远比不过桌面版的 GhostScript。
PDF 文件的解剖
一个 PDF 由 4 部分组成:
- 文本流 — PDF 里的文字,以矢量形式存储(不是图片)
- 图像流 — PDF 里的图片,通常是 JPEG / PNG 压缩过的,也可能没压缩
- 字体 — 嵌入的字体文件(可能重复嵌入,可能子集嵌入)
- 元数据 — 作者、创建软件、修改历史等
压缩能做的无非是这 4 件事:重新压缩图像(减小图像流)、重写字典(去除未引用的字体字符)、Deflate 文本流(zip-like)、去除冗余元数据。
浏览器里的 pdf-lib 工具主要做第 4 件(元数据精简)和第 1 件中的简单情形(已压缩 JPEG 的 metadata cleanup)。它不能做的事是:重新编码未优化的扫描图像、强制子集化字体、深度重排 PDF 对象结构。
4 种 PDF 类型的实测压缩比
类型 1:扫描件 PDF
特点: 每一页是一张高分辨率图(通常 200-300 DPI,JPEG 压缩)。整份 PDF 90% 的体积来自图像流。
预期压缩: 30-70%
示例: 5 MB 的扫描合同 → 1.5-3.5 MB
为什么浏览器压不动: 压缩扫描件需要重编码 JPEG(把 quality=85 降到 quality=70,或者转 WebP),这需要解码原图。浏览器工具有限,所以我们 v1 不支持这种压缩。桌面工具(GhostScript、Adobe Acrobat、Foxit)做得到,代价是装软件。
怎么手动压缩: 把 PDF 每页导出成 JPEG(用 PDF 阅读器或 pdf-lib),再用 图片压缩 把 JPEG 压到 quality=70,然后用一个空 PDF 把这些图组合回去。这是手工方法,慢但有效。
类型 2:纯文字 PDF
特点: 文本流为主,字体已子集化,几乎没图或很少图。
预期压缩: 2-10%
示例: 1 MB 的研究报告(无图) → 0.9-0.98 MB
为什么浏览器做得到: 元数据精简 + Deflate 文本流,这就是 pdf-lib useObjectStreams: true 做的事。
类型 3:混合 PDF(文字 + 图)
特点: 比如产品手册、报告、PPT 导出 PDF — 有图表、有文字、有封面图。
预期压缩: 10-30%
示例: 8 MB 的产品手册 → 5.6-7.2 MB
为什么浏览器做得到一部分: 元数据精简 + 文本流 Deflate 全部生效;图像部分如果本来就是压缩过的(JPEG quality 80+),浏览器没办法再压。如果里面的图是 PNG 或高质量 JPEG,理论上有空间。
类型 4:加密 PDF
预期压缩: 0%(不能压缩加密内容)
为什么: 加密后内容是随机字节流,任何有意义的压缩算法都对它失效。你必须先解密,再压缩,再加密(如果你还需要加密)。
为什么本地工具永远比不过桌面 GhostScript
GhostScript(gs)是 PDF 压缩领域的瑞士军刀,核心能力是:
- 完全重排 PDF 对象图谱 — 把页内容、字体、图像重新交织,有利于增量更新(我们做不到)
- 图像重新编码 — 把 JPEG/PNG 重编码为更激进的 quality(我们做不到)
- 字体子集化 — 把嵌入字体从 100 KB 压到只嵌入”实际用到的字符”(我们做不到 — 需要渲染引擎)
- stream 滤波 — 改用更高效的 zlib level(我们做的是 baseline deflate)
GhostScript 要装 200 MB,而且有很多命令行参数(-dPDFSETTINGS=/screen 是最大压缩,/prepress 是最高质量)。浏览器侧完全做不到这些 — TypeScript 跑在沙箱里,没有底层 PDF 渲染管线。
我们 v1 怎么压缩的
我们的 PDF 工具 的「压缩」按钮做 3 件事:
useObjectStreams: true— 把多个 PDF 对象合并到一个压缩流,实测省 5-15% 体积。- 去除默认页 — pdf-lib 默认会加一个空页,我们去掉。
- 去除冗余元数据 — 比如
Producer、Creator、ModDate,如果工具链不需要就省掉。
如果你压完的 PDF 看不到明显体积变化(比如 5 MB → 4.95 MB),工具会礼貌地告诉你”已经压缩得很好了”。这是一个诚实反馈 — 不是说”我压了所以减了 30%“,而是”你的 PDF 没什么可减的”。
v2 计划
我们正在评估:
@pdf-lib/original的实验性图像重编码 API(社区有 PR,2026 Q3 可能在主分支合入)pdfjs-distworker 渲染 + canvas → WebP —— 拿 PDFjs 渲染每页到画布,导出 WebP,重新打包。这是手动压缩的方法 #1 的工具化版本,会显著增加 bundle(+30 MB)
v2 之前如果你需要激进压缩,没有捷径 — 装一个桌面工具(GhostScript、PDFsam、NAPS2)或用付费在线服务(smallpdf、ilovepdf)。
推荐做法
- 先看类型 — 用 PDF 阅读器打开文件,快速判断(全是文字?全是图?混合?)
- 别期望奇迹 — 纯文字 PDF 压不动,不要循环压缩(每轮只会减一点点反而越压越慢)
- 小批量 — 一次压 10 个以内,等结果出来再压下一批
- 压完打开看 — 重新打开压缩过的 PDF,没有”看着对”的视觉测试,只有”亲眼翻一遍”的视觉测试
试试我们的 PDF 工具 — 压缩模式,诚实告诉你能压多少。