如何从PDF中删除所有图片?

12

我想从PDF文件中删除所有图片。

页面布局不应更改。所有图片都应替换为空白。

  • 如何借助Ghostscript和适当的PostScript代码实现此目标?

那么,到底是谁认为他最好对这个问题进行了负面评价?为什么?请随意点踩,但请留下评论告诉我原因。 - Kurt Pfeifle
2个回答

22

与此同时,最新的Ghostscript版本有一种更好、更易于使用的方法,可以从PDF中删除所有的图像。要在命令行中添加的参数是-dFILTERIMAGE

 gs -o noimages.pdf -sDEVICE=pdfwrite -dFILTERIMAGE input.pdf
更好的是,您还可以通过指定-dFILTERTEXT-dFILTERVECTOR来从PDF中删除所有文本或所有矢量绘图元素。

当然,您也可以结合任何组合的这些-dFILTER*参数以达到所需的结果。(将所有三个组合当然会导致“空”页面。)

下面是包含上述三种类型内容的示例PDF页面的屏幕截图:


原始PDF页面的屏幕截图,其中包含“图像”,“矢量”和“文本”元素。
包含"图像","矢量"和"文本"元素的原始PDF页面的屏幕截图。


运行以下6个命令将创建剩余内容的所有6种可能变化:

 gs -o noIMG.pdf   -sDEVICE=pdfwrite -dFILTERIMAGE                input.pdf
 gs -o noTXT.pdf   -sDEVICE=pdfwrite -dFILTERTEXT                 input.pdf
 gs -o noVCT.pdf   -sDEVICE=pdfwrite -dFILTERVECTOR               input.pdf
gs -o onlyTXT.pdf -sDEVICE=pdfwrite -dFILTERVECTOR -dFILTERIMAGE input.pdf gs -o onlyIMG.pdf -sDEVICE=pdfwrite -dFILTERVECTOR -dFILTERTEXT input.pdf gs -o onlyVCT.pdf -sDEVICE=pdfwrite -dFILTERIMAGE -dFILTERTEXT input.pdf

下面的图像说明了结果:


顶部行:从左到右:删除所有“文本”;删除所有“图像”;删除所有“矢量”。底部行:从左到右:仅保留“文本”;仅保留“图像”;仅保留“矢量”。
顶部行,从左到右:删除所有"文本";删除所有"图像";删除所有"矢量". 底部行,从左到右:仅保留"文本";仅保留"图像";仅保留"矢量".



我们能否删除特定的向量?如果可以,如何在pdf本身中识别不同的向量。我测试过了,它可以工作,但它也会删除一些我不想要的向量。 - Jay Chakra
@JayChakra:不,您不能删除特定的向量。(但是,您可以将所有向量的删除限制在某个页面或页面范围内,然后将这些页面重新插入到原始PDF文档中。) - Kurt Pfeifle
1
你的图片似乎没有按照上面输入的命令排序。这里的“过滤”X是指在输出中不包括X,对吗? - Geremia
2
@Geremia:你关于命令顺序的想法是正确的。我已经进行了更改,谢谢。 (至少图像捕获已经保持了正确的描述。)关于参数名称:我同意“FILTERxxx”不是最好的选择 - 或许将它们命名为“REMOVExxx”会更加用户友好。 - Kurt Pfeifle

10

我自己提供答案,但实际代码是基于 Ghostscript 开发者 Chris Liddell 的精彩贡献。

我使用了他原来的 PostScript 代码,并剥离了其中的其他功能, 只保留删除 光栅图像 的函数。 其他图形页面对象 -- 文本部分、图案和向量对象 -- 应该保持不变。

请复制以下代码并将其保存为 remove-images.ps:

%!PS

% Run as:
%
%      gs ..... -dFILTERIMAGE -dDELAYBIND -dWRITESYSTEMDICT \
%                 ..... remove-images.ps <your-input-file>
%
% derived from Chris Liddell's original 'filter-obs.ps' script
% Adapted by @pdfkungfoo (on Twitter)

currentglobal true setglobal

32 dict begin

/debugprint     { systemdict /DUMPDEBUG .knownget { {print flush} if} 
                {pop} ifelse } bind def

/pushnulldevice {
  systemdict exch .knownget not
  {
    //false
  } if

  {
    gsave
    matrix currentmatrix
    nulldevice
    setmatrix
  } if
} bind def

/popnulldevice {
  systemdict exch .knownget not
  {
    //false
  } if
  {
    % this is hacky - some operators clear the current point
    % i.e.
    { currentpoint } stopped
    { grestore }
    { grestore moveto} ifelse
  } if
} bind def

/sgd {systemdict exch get def} bind def

systemdict begin

/_image /image sgd
/_imagemask /imagemask sgd
/_colorimage /colorimage sgd

/image {
   (\nIMAGE\n) //debugprint exec /FILTERIMAGE //pushnulldevice exec
  _image
  /FILTERIMAGE //popnulldevice exec
} bind def

/imagemask
{
  (\nIMAGEMASK\n) //debugprint exec
  /FILTERIMAGE //pushnulldevice exec
  _imagemask
  /FILTERIMAGE //popnulldevice exec
} bind def

/colorimage
{
  (\nCOLORIMAGE\n) //debugprint exec
  /FILTERIMAGE //pushnulldevice exec
  _colorimage
  /FILTERIMAGE //popnulldevice exec
} bind def

end
end

.bindnow

setglobal

现在运行此命令:

gs -o no-more-images-in-sample.pdf \
   -sDEVICE=pdfwrite               \
   -dFILTERIMAGE                   \
   -dDELAYBIND                     \
   -dWRITESYSTEMDICT               \
    remove-images.ps               \
    sample.pdf

我使用官方PDF规范测试了代码,并且测试成功。下面两张截图展示了输入和输出PDF文件的第750页:

如果你想知道为什么看起来像图片的东西仍然出现在输出页面上:那是因为它不是真正的光栅图像,而是原始文件中的“pattern”,因此没有被删除。


就我所知,我希望在未来的GS版本中将Chris代码的系统级版本集成进去。这样,在所有设备上都可以实现,而无需额外的工作。不过也不要抱太大希望…… - KenS
在给出的命令中,缺少对 remove-images.ps 的引用 - 它应该是倒数第二个参数,在 sample.pdf 之前。 - akobel
@perpeduumimmobile:哈!你说得对!感谢你的发现和报告。 - Kurt Pfeifle
@KenS:现在Git源代码中是否包含了Chris代码的“系统级版本”,作为“子类化”内容的一部分? - Kurt Pfeifle
非常敏锐,确实是今天下午提交的。它是“对象过滤”,但请注意,它与Chris的不完全相同,因为它在图形库中工作,而不是语言中。尽管如此,这具有一个优点,即它可以与所有可能的输入语言一起使用。 - KenS
显示剩余2条评论

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