如何在python中获取两个PDF文件的差异?

时间:2009-08-21 09:01:37

标签: python pdf

我需要找到两个pdf文件之间的区别。是否有任何与python相关的工具都有一个直接给出2个PDF的差异的功能?

5 个答案:

答案 0 :(得分:5)

“差异”是什么意思? PDF文本或某些布局更改的差异(例如,调整了嵌入图形的大小)。第一个很容易检测,第二个几乎不可能得到(PDF是一种非常复杂的文件格式,提供无限的文件格式化功能)。

如果你想获得文本差异,只需在两个PDF上运行pdf to text实用程序,然后使用Python的内置差异库来获得转换文本的差异。

这个问题涉及python中的pdf到文本转换:Python module for converting PDF to text

此方法的可靠性取决于您使用的PDF生成器。如果您使用例如Adobe Acrobat和一些基于Ghostscript的PDF-Creator可以从SAME word文档制作两个PDF,尽管源文档是相同的,但您仍然可以获得差异。

这是因为有许多方法可以将源文档的信息编码为PDF,并且每个转换器使用不同的方法。通常,pdf到文本转换器无法确定正确的文本流,尤其是对于复杂的布局或表格。

答案 1 :(得分:3)

我不知道你的用例,但是对于使用reportlab生成pdf的脚本的回归测试,我做了pdfs by

  1. 使用ghostsript将每个页面转换为图像
  2. 使用PIL
  3. 将每个页面与标准pdf的页面图像区分开来

    e.g

    im1 = Image.open(imagePath1)
    im2 = Image.open(imagePath2)
    
    imDiff = ImageChops.difference(im1, im2)
    

    这适用于标记由于代码更改而引入的任何更改。

答案 2 :(得分:2)

在我加密的pdf unittest上遇到同样的问题,pdfminer和pyPdf都不适合我。

这两个命令(pdftocairo,pdftotext)在我的测试中非常完美。 (Ubuntu安装:apt-get install poppler-utils)

您可以通过以下方式获取pdf内容:

from subprocess import Popen, PIPE

def get_formatted_content(pdf_content):
    cmd = 'pdftocairo -pdf - -' # you can replace "pdftocairo -pdf" with "pdftotext" if you want to get diff info
    ps = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    stdout, stderr = ps.communicate(input=pdf_content)
    if ps.returncode != 0:
        raise OSError(ps.returncode, cmd, stderr)
    return stdout

似乎pdftocairo可以重绘pdf文件,pdftotext可以提取所有文本。

然后你可以比较两个pdf文件:

c1 = get_formatted_content(open('f1.pdf').read())
c2 = get_formatted_content(open('f2.pdf').read())
print(cmp(c1, c2)) # for binary compare
# import difflib
# print(list(difflib.unified_diff(c1, c2))) # for text compare

答案 3 :(得分:0)

检查一下,它可能很有用:http://pybrary.net/pyPdf/

答案 4 :(得分:0)

即使这个问题很老,我的猜测是我可以为这个话题做出贡献。

我们有几个应用程序可生成大量PDF。其中一个应用程序是用Python编写的,最近我想编写集成测试来检查PDF生成是否正常工作。

测试PDF生成是 HARD ,因为PDF文件的规范非常复杂且不确定。使用完全相同的输入数据生成的两个PDF将生成不同的文件,因此直接文件比较将被丢弃。

解决方案:我们必须继续测试它们的外观(因为应该是确定性的!)

在我们的例子中,PDF是使用reportlab包生成的,但是从测试角度来看这并不重要,我们只需要生成器的文件名或PDF blob(字节)即可。我们还需要一个包含“良好” PDF的期望文件,以便与来自生成器的PDF进行比较。

将PDF转换为图像,然后进行比较。可以通过多种方式完成此操作,但是我们决定使用ImageMagick,因为它用途广泛且非常成熟,几乎所有编程语言都具有绑定。对于Python 3,绑定由Wand包提供。

该测试如下所示。删除了我们实施的具体细节,并简化了示例:

import os
from unittest import TestCase
from wand.image import Image
from app.generators.pdf import PdfGenerator


DIR = os.path.dirname(__file__)


class PdfGeneratorTest(TestCase):

    def test_generated_pdf_should_match_expectation(self):
        # `pdf` is the blob of the generated PDF
        # If using reportlab, this is what you get calling `getpdfdata()`
        # on a Canvas instance, after all the drawing is complete
        pdf = PdfGenerator().generate()

        # PDFs are vectorial, so we need to set a resolution when
        # converting to an image
        actual_img = Image(blob=pdf, resolution=150)

        filename = os.path.join(DIR, 'expected.pdf')

        # Make sure to use the same resolution as above
        with Image(filename=filename, resolution=150) as expected:
            diff = actual.compare(expected, metric='root_mean_square')
            self.assertLess(diff[1], 0.01)

0.01尽可能低,我们可以容忍很小的差异。考虑到diff[1]使用root_mean_square指标在0到1之间变化,因此与样本预期文件相比,我们在这里接受所有通道上的差异最多为1%。