如何压缩 PDF 文件, imagemagick, Ghostscript, NodeJS

作者: 科技微讯

日期:

为什么要压缩 PDF 文档

我用 iPad 扫描了一些文件, 想把它保存在印象笔记, 但文件体积有点大, 同步时间可能有点久. 有很多在线压缩 PDF 文件的网站, 不过需要把文件上传到他们的服务器, 再从他们的服务器下载下来, 效率有点低.

我需要一种本地压缩 PDF 文件的方法. 我用 Mac, 苹果官网介绍了如何使用预览应用压缩 PDF, 但压缩后太模糊, 完全不能用. 研究了一番, 找到了一种比较好的方法.

如何压缩 PDF 文档, 以 Mac 为例

分享三种方法.

使用 Ghostscript

  • 在电脑本地安装 Ghostscript, Mac 用户可以用 brew 安装, 如果卡在 updating homebrew..., control + C 一次, 再稍等.
  • 接着打开 Shrinkpdf: shrink PDF files with Ghostscript, 把它提供的 shrinkpdf.sh 文件下载到电脑.
  • 打开终端应用, 通过 cd 进入 shrinkpdf.sh 所在的路径, 然后使用 sh shrinkpdf.sh input.pdf output.pdf 144 这样的命令压缩 pdf 文件.

其中的 input.pdf 是需要压缩的 pdf 文件, output.pdf 是最后生成的文件, 通过 144 设置目标文件的 DPI, 144 是比较理想的值, 数值越小体积越小, 当然也越模糊.

使用 imagemagick

imagemagick 有很多功能, 可以把 pdf 文件转换成图片, 或者反过来把多个图片合并成一个 pdf, 等等. 当涉及 pdf 操作时, 似乎都需要 Ghostscript 的支持, 所以首先在电脑安装 Ghostscript 和 imagemagick, 用 brew 安装即可.

imagemagick 压缩 pdf 的思路如下:

  • 把 pdf 每一页转换成图片: convert -density 144 file.pdf image.jpg
  • 压缩图片: convert -sampling-factor 4:2:0 -strip -quality 60 -interlace JPEG -colorspace RGB image*.jpg output.jpg
  • 把压缩后的图片重新合并成一个 pdf 文件: convert output*.jpg -quality 60 output.pdf

关于压缩图片所使用的 -sampling-factor 4:2:0 -strip -quality 60 -interlace JPEG -colorspace RGB, 可参考stackoverflow的一个问答.

使用 imagemagick 压缩 pdf 有一个大缺点. 如果这个 pdf 是扫描件, 这样压缩效果很好, 但是如果 pdf 的内容是矢量内容, 例如 word 文档转换过来的等等, 这样反而会增加生成的 pdf 文件的体积. 因为 imagemagick 把矢量内容栅格化了, 页面都变成了图片, 而 shrinkpdf.sh 不存在这个问题.

NodeJS

单纯用 nodejs 我没有找到很好的压缩 pdf 的方法, 比较推荐的做法是:

const { exec } = require('child_process')
exec('sh shrinkpdf.sh input.pdf output.pdf 144')

归根到底还是用 Ghostscript, 所以如果你在 nodejs 服务器应用这种方法, 需要先在服务器安装 Ghostscript 和 imagemagick.

如何让 PDF 看起来是扫描出来的样子

2020/05/16 补充.

Hacker News 有一个帖子分享了多种把 PDF 转换成看起来是用扫描仪扫描出来的样子的方法, 例如:

convert -density 150 ORIGINAL.pdf -colorspace gray +noise Gaussian -rotate 0.5 -depth 2 SCANNED.pdf