使用pyPdf合并非标准PDF文件

2 投票
1 回答
2531 浏览
提问于 2025-04-17 17:42

我想把几个PDF文件合并成一个PDF文档。但是,输入的文件似乎不完全符合标准。文件的结束标记后面还有一些额外的信息:

>>
startxref
1994481
%%EOF

%%PPIRoute: 4

显然,这导致pyPdf 给我抛出了一个异常

pyPdf.utils.PdfReadError: EOF marker not found

现在问题来了:我该怎么办呢?我可以打开每个文件,去掉最后两行,然后再保存,这样再放进pyPdf里。不过,我不是很喜欢这个主意。也许还有更好的办法?

1 个回答

3

我建议把pdf.py脚本中PdfFileReader类的read()方法开头的代码从:

    def read(self, stream):
        # start at the end:
        stream.seek(-1, 2)
        line = ''
        while not line:
            line = self.readNextEndLine(stream)
        if line[:5] != "%%EOF":
            raise utils.PdfReadError, "EOF marker not found"

    ... etc

改成:

    def read(self, stream):
        # start at the end:
        stream.seek(-1, 2)
        line = ''
        # read stream backwards while watching for end-of-file marker
        while line[:5] != "%%EOF":
            line = self.readNextEndLine(stream)

    ... etc

我觉得原来的代码并没有真正做到Adobe的PDF 1.3参考文档中第3.4.4节“文件尾部”(第628页)所暗示的内容,文中提到(我的强调):

Acrobat查看器只要求%%EOF标记出现在文件最后1024个字节中的某个地方。

换句话说,在"%%EOF"标记之后,文件的物理末尾之前可以有其他内容。我的修改尝试考虑到这一点,让程序忽略标记后面可能附加的其他内容,而不是抛出异常(不过这并不要求"%%EOF"一定要在最后1K字节内,虽然可以加个检查)。这也意味着你想合并的文件实际上可能是符合规范的。

更新:

这是一个版本,它也要求"%%EOF"标记在最后1024个字节内:

def read(self, stream):
    # start at the end
    stream.seek(-1, os.SEEK_END)
    last1K = stream.tell() - 1024 + 1 # offset of last 1024 bytes of stream

    # read stream backwards while watching for end-of-file marker
    line = ''
    while line[:5] != "%%EOF":
        line = self.readNextEndLine(stream)
        if stream.tell() < last1K:
            raise utils.PdfReadError, "EOF marker not found"

    ... etc

撰写回答