我需要找到两个pdf文件之间的区别。是否有任何与python相关的工具都有一个直接给出2个PDF的差异的功能?
答案 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
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%。