优化PDF文件(使用Ghostscript或其他工具)

62

如果您想优化PDF文件并尽可能减小文件大小,Ghostscript是否是最佳选择?

我需要存储大量PDF文件,因此需要尽可能地优化和减小文件大小。

有人使用过Ghostscript或其他工具吗?

命令行

exec('gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dCompatibilityLevel=1.4
-dPDFSETTINGS=/screen -sOutputFile='.$file_new.' '.$file);

你只寻找免费软件吗?还是专有付费软件也可以考虑? - Kurt Pfeifle
你有没有想过如何知道PDF文件中哪些对象占用了最多的空间?是字体还是高分辨率图片? - Kurt Pfeifle
另请参考pdfsizeopt工具(GPLv2) https://askubuntu.com/a/1011292/19753 - imz -- Ivan Zakharyaschev
9个回答

104
如果您正在寻找一个自由软件,Ghostscript 绝对是您的最佳选择。但是,它并不总是易于使用——其中一些非常强大的处理选项并没有很好地记录。请查看这个答案,它解释了如何实现比通用的“-dPDFSETTINGS=/screen”更详细的图像分辨率降采样控制(该选项定义了一些整体默认值,您可能想要覆盖):如何在 PDF 文件中降低图像分辨率?。基本上,它告诉您如何使 Ghostscript 将所有图像降采样到 72dpi 的分辨率(这个值是“-dPDFSETTINGS=/screen”使用的值——您甚至可以将其降低)。
-dDownsampleColorImages=true \
-dDownsampleGrayImages=true \
-dDownsampleMonoImages=true \
-dColorImageResolution=72 \
-dGrayImageResolution=72 \
-dMonoImageResolution=72 \

如果您想尝试Ghostscript是否也能够“取消嵌入”所使用的字体(有时可以,有时不行--这取决于嵌入字体的复杂性,以及所使用的字体类型),您可以尝试将以下内容添加到您的gs命令中:

gs \
  -o output.pdf \
   [...other options...] \
  -dEmbedAllFonts=false \
  -dSubsetFonts=true \
  -dConvertCMYKImagesToRGB=true \
  -dCompressFonts=true \
  -c ".setpdfwrite <</AlwaysEmbed [ ]>> setdistillerparams" \
  -c ".setpdfwrite <</NeverEmbed [/Courier /Courier-Bold /Courier-Oblique /Courier-BoldOblique /Helvetica /Helvetica-Bold /Helvetica-Oblique /Helvetica-BoldOblique /Times-Roman /Times-Bold /Times-Italic /Times-BoldItalic /Symbol /ZapfDingbats /Arial]>> setdistillerparams" \
  -f input.pdf

注意:降低图像分辨率肯定会降低质量(不可逆),取消嵌入字体将使PDF难以或无法显示和打印,除非在计算机上安装了相同的字体。

更新

在我原始的回答中忽略了一个选项,即添加:

-dDetectDuplicateImages=true

该参数会导致Ghostscript尝试检测PDF中嵌入的任何图像是否被多次使用。如果您将图像用作徽标或页面背景,并且PDF生成软件未针对此情况进行优化,则可能会发生这种情况。在旧版OpenOffice/LibreOffice中曾经出现过这种情况(我测试了最新版本的LibreOffice,v4.3.5.2,它不再做这种愚蠢的事情)。
如果您使用pdftk连接PDF文件,也会发生这种情况。为了向您展示其效果以及如何发现它,让我们看一个示例PDF文件:
pdfinfo p1.pdf

 Producer:       libtiff / tiff2pdf - 20120922
 CreationDate:   Tue Jan  6 19:36:34 2015
 ModDate:        Tue Jan  6 19:36:34 2015
 Tagged:         no
 UserProperties: no
 Suspects:       no
 Form:           none
 JavaScript:     no
 Pages:          1
 Encrypted:      no
 Page size:      595 x 842 pts (A4)
 Page rot:       0
 File size:      20983 bytes
 Optimized:      no
 PDF version:    1.1

近期版本的Poppler的pdfimages工具增加了对-list参数的支持,该参数可以列出PDF文件中包含的所有图像:
pdfimages -list p1.pdf

 page num  type width height color comp bpc  enc interp objectID x-ppi y-ppi size ratio
 --------------------------------------------------------------------------------------
    1   0 image    423   600   rgb    3   8 jpeg     no     7  0    52    52 19.2K 2.6%

这个示例PDF是一个1页的文档,包含一张图片,使用JPEG压缩,宽度为423像素,高度为600像素,在页面上以52PPI的分辨率呈现。
如果我们使用pdftk将三份副本连接起来,就像这样:
pdftk p1.pdf p1.pdf p1.pdf cat output p3.pdf

然后通过 pdfimages -list 显示这些图像属性的结果:

pdfimages -list p3.pdf

 page num  type width height color comp bpc  enc interp objectID x-ppi y-ppi size ratio
 --------------------------------------------------------------------------------------
    1   0 image   423    600   rgb    3   8 jpeg     no     4  0    52    52 19.2K 2.6%
    2   1 image   423    600   rgb    3   8 jpeg     no     8  0    52    52 19.2K 2.6%
    3   2 image   423    600   rgb    3   8 jpeg     no    12  0    52    52 19.2K 2.6%

这表明现在有3个相同的PDF对象(ID为4、8和12)嵌入到p3.pdf中。 p3.pdf由3页组成:
pdfinfo p3.pdf | grep Pages:

 Pages:          3

通过替换重复图像为引用来优化PDF

现在我们可以借助Ghostscript应用上述提到的优化方法。

 gs -o p3-optim.pdf -sDEVICE=pdfwrite -dDetectDuplicateImages=true p3.pdf

检查:

 pdfimages -list p3-optim.pdf

 page num  type width height color comp bpc  enc interp objectID x-ppi y-ppi size ratio
 --------------------------------------------------------------------------------------
    1   0 image   423    600   rgb    3   8 jpeg     no    10  0    52    52 19.2K 2.6%
    2   1 image   423    600   rgb    3   8 jpeg     no    10  0    52    52 19.2K 2.6%
    3   2 image   423    600   rgb    3   8 jpeg     no    10  0    52    52 19.2K 2.6%

每页仍然只列出一张图片,但是PDF对象ID现在始终相同:10。
 ls -ltrh p1.pdf p3.pdf p3-optim.pdf

   -rw-r--r--@ 1 kp  staff    20K Jan  6 19:36 p1.pdf
   -rw-r--r--  1 kp  staff    60K Jan  6 19:37 p3.pdf
   -rw-r--r--  1 kp  staff    16K Jan  6 19:40 p3-optim.pdf

如您所见,使用pdftk进行“愚蠢”的拼接将原文件大小增加了三倍。通过Ghostscript的优化,文件大小大大降低。
最新版本的Ghostscript甚至可以默认应用-dDetectDuplicateImages选项。(据我所知,首次引入该选项的v9.02版本并不默认使用它。)

谢谢你的回答 :) 我已经测试过了,但是当你手动将dpi设置为72时,与设置/screen时相比质量会降低,而且文件大小仍然比/screen设置下要小 :) - clarkk
我的意思是.. 使用/screen选项的质量更好,与手动设置dpi为72相比,文件大小更小。 - clarkk
@clarkk:我很想看一份展示这种情况的PDF样本。你能提供一个吗(或者这会侵犯某人的隐私)? - Kurt Pfeifle
在此处查看http://www.dynaccount.com/tmp/35.pdf和http://www.dynaccount.com/tmp/36.pdf。查看文档顶部的徽标。 35.pdf(44.81kb-手动dpi)和36.pdf(44.73kb- /屏幕) - clarkk
@clarkk:为了确保我理解正确——这两个文件是两个转换命令的结果吗?(我对你的原始PDF文件之一感兴趣,这样我就可以自己玩转转换参数....) - Kurt Pfeifle
3
为了完整起见,可以用GhostScript/ps2pdf转换PDF的选项列表可以在此处找到:http://ghostscript.com/doc/current/Ps2pdf.htm - Simon A. Eugster

37

你可以通过将PDF转换为Postscript,然后再转换回PDF来获得良好的结果,使用:

pdf2ps file.pdf file.ps
ps2pdf -dPDFSETTINGS=/ebook file.ps file-optimized.pdf

参数-dPDFSETTINGS的值定义了生成PDF时图像的质量。选项从低到高分别为:/screen/default/ebook/printer/prepress,请参考http://milan.kupcevic.net/ghostscript-ps-pdf/

Postscript文件可能会变得很大,但结果是值得的。我从一个60 MB的PDF文件转换为一个140 MB的Postscript文件,然后再优化成1.1 MB大小的PDF文件。


在Windows环境下如何做这件事,获得一些帮助将是非常棒的。 - Serj Sagan
为什么这样做会比只使用适当设置的 gs 生成更小的文件呢?此外,这样做会导致一些问题,因为Postscript缺少某些功能(例如alpha透明度、渐变、ICC配置文件)。 - Mikko Rantalainen
我不知道,只是报告在我的情况下运行良好的内容,希望其他人也能从中受益。请随意发布更好的解决方案或帮助改进现有的解决方案。 - Martijn de Milliano
2
第一步是不必要的。ps2pdf将接受PDF输入文件。 - frabjous
@frabjous 对我来说,先转换为ps格式会有很大的改善。这是使用版本9.26的ps2pdf和pdf2ps。 - ariddell
@ariddell 对我来说,直接使用ps2pdf得到了更小的文件。因此,似乎值得尝试两种方法(或者理解背后的规则)。 - dalanicolai

10

我使用Ghostscript,并采用以下选项,这些选项来自此处.

gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen \
 -dNOPAUSE -dQUIET -dBATCH -sOutputFile=output.pdf input.pdf

1
请注意,虽然这个通常运行良好,但对于可填写的PDF文件,它将无法正常工作。 - Alex Flo
@AlexFlo,你会用什么命令来实现这个?我现在被卡住了。 - Wild Will

7

您可能会发现来自Popplerpdftocairo可以制作更小的PDF文件,但请注意它会剥离一些功能(例如超链接)。


谢谢,我发现ps2pdf14有时会改变输出结果,在这种情况下,pdftocairo将PDF文件缩小(从500K到110K),但是裁剪了一部分,所以我在保存为PDF之前在Inkscape中添加了明确的边距,然后通过pdftocairo然后通过pdfcrop(来自TeX)使其缩小到90K。 - mirabilos

3

2
您将会失去部分质量,但如果不是问题的话,ImageMagick的convert可能会有所帮助:
convert original.pdf reduced.pdf

请注意,这种方法并不总是有效的:我曾经使用这个命令把一个126MB的文件转换成了14MB,但另一次却将一个350Ko的文件大小加倍。
无论如何,值得一试...
正如评论中所提到的,当然没有必要在矢量 PDF 上应用此命令,它只对栅格化图像有用。
请参见此帖子以获取相关选项。

4
这仅适用于基于扫描图像的PDF文件,否则ImageMagick会将您基于向量的PDF转换为光栅图像,结果文件实际上可能比原始文件更大。 - yms
@yms: 当然,我认为你对基于向量的PDF文件的看法是正确的,但是我相信它对于任何一种栅格图像都有意义,其中扫描图像只是其中很小的一部分。在我的情况下,这个文档是由普通数字照片制成的。 - Skippy le Grand Gourou
1
当然,我指的是扫描图像作为PDF文件的最常见用例,其中只包含光栅图像(也许还有来自OCR的一些透明文本)。我只是想将此评论添加为对任何想使用您的解决方案的人的备注。 - yms

2

Ghostscript附带ps2pdf14实用程序,可用于优化PDF文件,但在某些情况下,“优化”后的文件大小可能比原始文件更大。


1
ps2pdf14 input.pdf output.pdf 执行的操作与 gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET -dBATCH -sOutputFile=output.pdf input.pdf 相同。对于纯文本内容,输出文件 output.pdf 的大小为输入文件的 25%。 - code_angel
1
pdfopt 生成的输出文件更大了。 - code_angel
6
pdfopt不再与ghostscript捆绑。 - frabjous

0
对于主要由嵌入图像(pdfimages -list 是你的好朋友)导致大小较大的 PDF,通常是扫描文档,我建议使用 ocrmypdf,它非常擅长优化,并提供可选的 OCR 层作为奖励。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接