是否存在一个适用于 Linux 的命令行工具,允许我从 PDF 中提取所有 /Subtype /Image 光栅图像对象,允许我使用另一个第三方工具处理它们,然后能够将它们重新插入到原始 PDF 中?
Debian 软件包 poppler-utils 带有工具 pdfimages,它允许我从 PDF 中提取所有图像,但在更改它们之后,我无法轻松地将它们重新插入到 PDF 中。
我之前写过简单的 PDF 解析器,所以我目前对这个问题的看法是
- 在 PDF 上运行 pdfclean(来自 mupdf 包)以解压缩所有流,从而使解析更容易
- 使用一个简单的解析器解析 pdf(当然这不能解析大多数 PDF,但只要它适用于我的 PDF,我就很高兴了)并将所有图像提取为位图,其名称中包含对象 id
- 使用第三方程序对图像进行一些操作
- 再次解析原始 pdf,但这次用修改后的图像替换里面的图像,并根据需要调整 /Length 和 /Filter
- 再次运行 pdfclean 以更正 xref 表中的所有偏移量
但是也许已经存在一个可以实现所有这些功能并且不局限于我编写的简单解析器的功能的工具?
如果您说不存在这样的工具,那么告诉我一个允许提取并随后替换图像的库也是可以的。
答案1
您可以尝试在命令行中使用 inkscape
inkscape -S # show all the object inside the document
inkscape --select=YouImage --verb=YourTransformation
inkscape --verb-list #to obtain all the possibilities
或者您可以提取图像,用任何您想要的东西(imagemagick?)修改它们,然后用 inkscape 在您的文档中替换它们。
问候
答案2
似乎目前还不能在命令行中执行此操作,但我找到了一种简单的方法,可以使用pdfrw python 模块像这样:
#!/usr/bin/env python
import sys
import os
import zlib
import Image
import StringIO
from pdfrw import PdfReader, PdfDict, PdfArray, PdfName, PdfWriter
def process_image(image):
if image["/Filter"] == PdfName("FlateDecode"):
pass
elif image["/Filter"] == PdfName("DCTDecode"):
im = Image.open(StringIO.StringIO(image.stream))
outf = StringIO.StringIO()
im.save(outf, "JPEG", quality=45)
image.stream = outf.getvalue()
outf.close()
def find_images(obj, visited=set()):
if not isinstance(obj, (PdfDict, PdfArray)):
return
myid = id(obj)
if myid in visited:
return
visited.add(myid)
if isinstance(obj, PdfDict):
if obj.Type == PdfName.XObject and obj.Subtype == PdfName.Image:
process_image(obj)
obj = obj.itervalues()
for item in obj:
find_images(item, visited)
if __name__ == '__main__':
inpfn,outfn = sys.argv[1:]
reader = PdfReader(inpfn)
find_images(reader)
PdfWriter().addpages(reader.pages).write(outfn)
您可以在函数中实现任何您想要的功能process_images
,甚至可以轻松完成诸如调用外部程序来修改当前图像之类的复杂操作。在此示例中,我们仅使用 PIL 重新编码质量为 45 的 jpeg 图像。