PDF 太大怎么压缩到指定大小:原理、Ghostscript 参数与 5 种实战方案

一、结论先给

PDF 大的原因只有三类,先定位再动手,否则就是瞎压。

# 30 秒定位:看体积构成
pdfinfo input.pdf            # 页数、页面尺寸
pdffonts input.pdf           # 字体占多少
pdfimages -list input.pdf    # 图片占多少、分辨率多少
成因 判断方法 压缩手段 效果
扫描/位图 pdfimages -list 有大图 降采样 + 降 JPEG 质量 最大,常见 10-20 倍
嵌入字体 pdffonts 有几百 KB 的全字库 字体子集化 中等,几百 KB 级
对象未压缩 老软件生成的 PDF qpdf --linearize / 重压缩流 小,10-30%

一句话结论:扫描件靠降采样,文字稿靠 Ghostscript 预设,剩下的边角靠 qpdf。

二、Ghostscript 四档预设:最快的一招

# 装
sudo apt install ghostscript

核心参数就一个:-dPDFSETTINGS

gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.5 \
   -dPDFSETTINGS=/ebook \
   -dNOPAUSE -dQUIET -dBATCH \
   -sOutputFile=out.pdf input.pdf

四档的含义与实测效果(50 页扫描件,原 48 MB,结果为估算):

预设 图像分辨率 适用场景 体积(估算) 观感
/screen 72 dpi 屏幕看、邮件附件 3-6 MB 文字边缘略毛躁,看图明显糊
/ebook 150 dpi 默认推荐,通用 8-15 MB 屏幕清晰,打印勉强
/printer 300 dpi 要打印 25-40 MB 打印没问题
/prepress 300 dpi + 保留色彩 印刷 40+ MB 几乎无损,体积基本没降

/screen 和 /ebook 是两个真正能用的档位。/printer 之后体积就没意义了。

⚠️ 注意:Ghostscript 重压缩会丢掉表单、注释、书签和部分元数据。有书签的文档压缩前先备份原文件。

三、手写参数:压得比预设更狠

预设不能满足时,手动控制图像参数:

gs -sDEVICE=pdfwrite \
   -dCompatibilityLevel=1.5 \
   -dDownsampleColorImages=true \
   -dColorImageResolution=150 \
   -dColorImageDownsampleType=/Bicubic \
   -dDownsampleGrayImages=true \
   -dGrayImageResolution=150 \
   -dGrayImageDownsampleType=/Bicubic \
   -dDownsampleMonoImages=true \
   -dMonoImageResolution=300 \
   -dMonoImageDownsampleType=/Subsample \
   -dAutoFilterColorImages=false \
   -dColorImageFilter=/DCTEncode \
   -dJPEGQ=70 \
   -dAutoFilterGrayImages=false \
   -dGrayImageFilter=/DCTEncode \
   -dNOPAUSE -dQUIET -dBATCH \
   -sOutputFile=out.pdf input.pdf

参数解释(这几个是真正起作用的):

参数 作用 建议值
-dColorImageResolution 彩色图降采样到多少 dpi 100-150
-dGrayImageResolution 灰度图 150
-dMonoImageResolution 黑白图(文字/线条) 300,别降,降了文字就毛
-dJPEGQ JPEG 质量 0-100 60-75
-dColorImageFilter=/DCTEncode 彩色图用 JPEG 压缩 必加
-dDetectDuplicateImages=true 重复图片只存一份 有重复 logo 时很有效

最容易忽略的一条:MonoImageResolution 一定要比彩色高。黑白图是文字主体,压到 150 dpi 会直接糊成一团——这是很多人压完觉得"字看不清"的根本原因。

四、扫描件的极限压缩:黑白二值化

扫描的文档类 PDF(合同、发票、书籍),最狠的一招是转成 1-bit 黑白:

# 先转图,再二值化,最后组回 PDF
pdftoppm -r 300 -gray input.pdf page
for f in page-*.pgm; do
  magick "$f" -threshold 60% -compress Group4 "${f%.pgm}.tif"
done
magick page-*.tif -compress Group4 out.pdf

体积对比(估算,300 dpi A4 单页):

方案 单页体积
原扫描彩色 JPG 500 KB - 1.5 MB
灰度 + JPEG q75 150-400 KB
黑白二值 + CCITT G4 30-80 KB

适用范围:纯文字的黑白文档。有照片、有灰度图的不要二值化,会丢信息。

五、压到"指定大小":二分法脚本

需求场景很常见:"这个 PDF 必须小于 2 MB 才能上传"。一次压不准,用脚本自动找参数:

#!/usr/bin/env bash
# usage: ./fit.sh input.pdf 2048   (目标 2048 KB)
set -euo pipefail
IN=$1; TARGET_KB=$2
OUT="${IN%.pdf}.small.pdf"

lo=40; hi=300; best=""
for i in $(seq 1 8); do
  mid=$(( (lo + hi) / 2 ))
  gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.5 -dNOPAUSE -dQUIET -dBATCH \
     -dDownsampleColorImages=true -dColorImageResolution=$mid \
     -dColorImageFilter=/DCTEncode -dJPEGQ=70 \
     -sOutputFile="$OUT" "$IN"
  size=$(( $(stat -c%s "$OUT") / 1024 ))
  echo "res=${mid}dpi size=${size}KB"
  if [ "$size" -le "$TARGET_KB" ]; then best=$mid; lo=$mid; else hi=$mid; fi
done
echo "---"
echo "最佳分辨率: ${best}dpi"
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.5 -dNOPAUSE -dQUIET -dBATCH \
   -dDownsampleColorImages=true -dColorImageResolution=${best:-72} \
   -dColorImageFilter=/DCTEncode -dJPEGQ=70 \
   -sOutputFile="$OUT" "$IN"
echo "最终: $(( $(stat -c%s "$OUT") / 1024 ))KB"

思路:用分辨率当变量做二分查找,8 次迭代内收敛。如果压到 72 dpi 还不达标,说明页数太多,只能拆分成多个文件(用 PDF 拆分)或接受更低质量。

六、另一条路:qpdf(无损重排,不动图像)

sudo apt install qpdf

# 重排对象流 + 开启压缩(不改变图像质量)
qpdf --linearize --compress-streams=y input.pdf out.pdf

# 去掉没用的对象(有孤儿对象时有效)
qpdf --linearize --remove-unreferenced-resources=yes input.pdf out.pdf

# 加密 PDF 要先解密才能压
qpdf --decrypt --password=xxx input.pdf tmp.pdf && gs ... tmp.pdf out.pdf

qpdf 不改变图像,所以压缩率有限(10-30%),但完全无损,适合那些已经压过、不能再损的文档。

还有个更狠的第三方工具 pdfsizeopt(需要 Java + 一堆依赖),能自动做字体子集化、图像重编码,压缩率常高于 Ghostscript,但环境搭建麻烦,服务器上偶尔值得装一次。

七、压缩后必须做的校验

压完不看就交付,是这类操作最大的坑。

# 1. 页数对不对(Ghostscript 偶尔会丢页)
pdfinfo out.pdf | grep Pages
pdfinfo input.pdf | grep Pages

# 2. 能不能正常打开、文字能不能选(渲染引擎报错会静默产出坏文件)
pdftotext out.pdf - | head -20

# 3. 加密状态(gs 有时会带上权限设置)
pdfinfo out.pdf | grep -i encrypted

# 4. 体积对比
ls -lh input.pdf out.pdf

自动化脚本里建议加一句断言:页数不一致就直接失败退出,别继续往下走。

八、常见误区

1. 反复压同一个文件 压过的 PDF 再压一次,体积几乎不降,质量却再掉一档。永远从原文件压。

2. 用在线工具传合同 压缩要读整个文件,传到别人服务器上就等于交出去了。合同、身份证、病历这类,用本地工具处理。

3. 以为压缩等于加密 压缩只是变小,不设任何权限。要防打开得单独加密(见 PDF 加密篇)。

4. 只看总体积不看用途 给领导看的 PDF 压到 72 dpi,字体发毛,比体积大 20 MB 更糟。先定用途,再定参数。

5. 忘了算磁盘 批量压几百个文件时,中间产物能轻易吃掉几十 GB。开跑前用 磁盘容量计算 估一下,中间目录放 /tmp 定期清。

九、几条纪律

  1. 先 pdfimages -list + pdffonts 定位,知道大头在哪再动手。
  2. 扫描件走降采样,黑白文档走二值化,其余走 /ebook 预设。
  3. 黑白图分辨率保持 300,只降彩色和灰度。
  4. 永远从原文件压,不压二次。
  5. 压完必查页数和可选中文字,自动化脚本里写死断言。
  6. 敏感文件不上在线工具,走本地。

十、延伸阅读

👉 相关在线工具:PDF 压缩 · PDF 拆分 · 图片压缩 · 磁盘容量计算,免登录、浏览器内处理。

还有 65 个免费在线工具

纯前端实现,不用注册,数据不上传服务器。

浏览全部工具