Ghostscript用于合并PDF并压缩结果

78

我发现了一个很棒的命令可以使用Ghostscript将多个PDF合并成一个:

gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=out.pdf in1.pdf in2.pdf

合并后的文件大小比两个PDF文件的总大小小。

只使用单个文件作为输入运行命令,输出文件仍然较小。

在Ghostscript上是否有选项可以在合并时只复制页面而不进行任何压缩?

如果没有,那么Ghostscript的压缩是否如此出色,以至于不会造成任何质量损失?

3个回答

85

以下是使用 pdfwrite 作为设备时可以传递的一些其他选项。根据该页面,如果您没有传递任何内容,则 -dPDFSETTINGS 会被设置为接近于 /screen 的值,尽管它不会更具体。您可以尝试将其设置为 -dPDFSETTINGS=/prepress,这样只会压缩高于300 dpi的内容。

gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile=out.pdf in1.pdf in2.pdf

另一种选择是 pdftk:

pdftk in1.pdf in2.pdf cat output out.pdf

4
感谢您推荐pdftk。对于简单的PDF文件连接,它似乎非常完美。 - Dr. Jan-Philip Gehrcke
1
顺便说一句:pdftk 在 CentOS/RHEL 7 上不可用。 - a coder
1
我曾经遇到过使用 gs 后丢失页面并且文件大小增加了10倍的情况。而 pdftk 只是简单地进行合并,没有做任何修改,同时速度也更快。 - admirabilis
感谢推荐pdftk。当PDF合并时似乎没有任何开销。最初我担心会有水印,但实际上并没有。+1 - user3437460

39
您观察到的一些大小优化可能来自Ghostscript清理未使用对象,其最近获得的字体优化改进(您是否使用最新版本的GS?!)以及可能发生的图像重新/下采样。
如果用于PDF-> PDF转换,则Ghostscript基本上会按以下方式操作:
1.读取带有所有对象的输入文件并将它们转换为其内部格式,以进行图形页面表示。
2.对内部格式中的页面内容执行在命令行上要求的操作。
3.写出一个全新的PDF。
这意味着对于大多数PDF-> PDF操作,您将拥有不同的PDF对象排序和编号,甚至对象的内部代码也可能已更改(即使您的眼睛没有发现输入和输出PDF之间的任何差异)。
默认情况下,Ghostscript还将压缩任何在原始文件中未经压缩的对象流(但这是无损压缩)。
现在,对于你非常简单的命令行,不包含任何操作要求,Ghostscript会默认使用-dPDFSETTINGS=/default参数,并相应地进行操作。请注意,保留HTML标签。
那么,/default PDFSETTINGS是什么?你有两个选项来找出答案:
  1. Read the manual. The large table in middle of this section gives an overview. You can see that this one -dPDFSETTINGS=/default in itself is just a shorthand for the several dozen other more specific settings which it represents. The link to the documentation given is for current HEAD of the development code and your actually used version may be different of course.

  2. Query (your own) Ghostscript for the detailed meaning of this setting. My answers to question 'Querying Ghostscript for the default options/settings of an output device...' and question 'What are PostScript dictionaries, and how can they be accessed (via Ghostscript)?' do elaborate a bit more on this. In short, to query Ghostscript for the details of its /default PDFSETTINGS, run this command:

     gs \
       -q \
       -dNODISPLAY \
       -c ".distillersettings /default get {exch ==only ( ) print ===} forall quit"
    

    You should get a result very similar to this:

      /Optimize false
      /DoThumbnails false
      /PreserveEPSInfo true
      /ColorConversionStrategy /LeaveColorUnchanged
      /DownsampleMonoImages false
      /EmbedAllFonts true
      /CannotEmbedFontPolicy /Warning
      /PreserveOPIComments true
      /GrayACSImageDict << /HSamples [2 1 1 2] /VSamples [2 1 1 2] /QFactor 0.9 /Blend 1 >>
      /DownsampleColorImages false
      /PreserveOverprintSettings true
      /CreateJobTicket false
      /AutoRotatePages /PageByPage
      /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]
      /ColorACSImageDict << /HSamples [2 1 1 2] /VSamples [2 1 1 2] /QFactor 0.9 /Blend 1 >>
      /DownsampleGrayImages false
      /UCRandBGInfo /Preserve
    

    The only point that stands out from these: you may want to change /AutoRotagePages from /PageByPage to /None. On the commandline you would put it as -dAutoRotatePages=/None.

    To give you a complete list of parameters which would specifically tell Ghostscript to employ as much of a passthrough mode as it possibly can to the input PDF by adding these parameters:

      -dAntiAliasColorImage=false \
      -dAntiAliasGrayImage=false \
      -dAntiAliasMonoImage=false \
      -dAutoFilterColorImages=false \
      -dAutoFilterGrayImages=false \
      -dDownsampleColorImages=false \
      -dDownsampleGrayImages=false \
      -dDownsampleMonoImages=false \
      -dColorConversionStrategy=/LeaveColorUnchanged \
      -dConvertCMYKImagesToRGB=false \
      -dConvertImagesToIndexed=false \
      -dUCRandBGInfo=/Preserve \
      -dPreserveHalftoneInfo=true \
      -dPreserveOPIComments=true \
      -dPreserveOverprintSettings=true \
    
所以您可以尝试这个命令:
gs                                              \
 -o output.pdf                                  \
 -sDEVICE=pdfwrite                              \
 -dAntiAliasColorImage=false                    \
 -dAntiAliasGrayImage=false                     \
 -dAntiAliasMonoImage=false                     \
 -dAutoFilterColorImages=false                  \
 -dAutoFilterGrayImages=false                   \
 -dDownsampleColorImages=false                  \
 -dDownsampleGrayImages=false                   \
 -dDownsampleMonoImages=false                   \
 -dColorConversionStrategy=/LeaveColorUnchanged \
 -dConvertCMYKImagesToRGB=false                 \
 -dConvertImagesToIndexed=false                 \
 -dUCRandBGInfo=/Preserve                       \
 -dPreserveHalftoneInfo=true                    \
 -dPreserveOPIComments=true                     \
 -dPreserveOverprintSettings=true               \
  input1.pdf                                    \
  input2.pdf

最后,正如Chris Haas已经暗示的那样:如果您特别不想要Ghostscript默认应用的任何优化,您也可以使用pdftkpdftk无法执行这些操作,但相对操作简单,速度较快(但生成的文件大小可能比Ghostscript更大)。


1
截至2016年3月,CentOS/RHEL 7尚不支持pdftk。 - a coder
1
你能否在命令行中应用 -dPDFSETTINGS= 设置中的一个,然后稍后只使用 -d* 设置来覆盖其中的一部分呢? - CMCDragonkai
1
@CMCDragonkai:是的,你可以这样做。(虽然我没有测试过,但如果这不起作用,那就是一个bug。) - Kurt Pfeifle
这里有一个重新打包的 pdftk 版本可在 Centos 7 上使用。https://www.linuxglobal.com/pdftk-works-on-centos-7/ - Ren

4

我在iOS终端上使用以下代码成功地递归压缩多个PDF文档。我发布这篇文章是因为我找不到一个能够让我直接复制粘贴使用的方法。

find . -name '*.pdf' | while read pdf; do gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/ebook -dNOPAUSE -dQUIET -dBATCH -sOutputFile="${pdf}_new.pdf" "$pdf"; done

注意,您可能需要不同的输出质量,因此可以按照以下方式更改“-dPDFSETTINGS”参数:
-dPDFSETTINGS=/screen:较低的质量,较小的大小。
-dPDFSETTINGS=/ebook:更好的质量,但稍大的PDF文件。
-dPDFSETTINGS=/prepress:与Acrobat Distiller“Prepress Optimized”设置类似的输出。
-dPDFSETTINGS=/printer:选择类似于Acrobat Distiller“Print Optimized”设置的输出。
-dPDFSETTINGS=/default:选择旨在在各种用途中有用的输出,可能以产生较大的输出文件为代价。

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