我正在编写一个使用 Cairo 图形库输出 PDF 文件的 CAD 应用程序。许多单元测试不需要实际生成 PDF 文件,例如计算对象的预期边界框。但是,我想确保在更改代码后生成的 PDF 文件“看起来”正确。有没有一种自动化的方法来做到这一点?我怎样才能尽可能地自动化?我是否需要目视检查每个生成的 PDF?我怎样才能在不拔头发的情况下解决这个问题?
5 回答
(另请参阅下面的更新!)
我在 Linux 上使用 shell 脚本做同样的事情
- ImageMagick 的
compare
命令 - 实用
pdftk
程序 - 鬼脚本(可选)
.bat
(将其移植到DOS/Windows 的批处理文件会相当容易。)
我的应用程序创建了一些“已知良好”的参考 PDF。将代码更改后新生成的 PDF 与这些参考 PDF 进行比较。比较是逐像素进行的,并保存为新的 PDF。在此 PDF 中,所有未更改的像素都涂成白色,而所有不同的像素都涂成红色。
以下是构建块:
pdftk
使用此命令将多页 PDF 文件拆分为多个单页 PDF:
pdftk reference.pdf burst output somewhere/reference_page_%03d.pdf
pdftk comparison.pdf burst output somewhere/comparison_page_%03d.pdf
比较
使用此命令为每个页面创建一个“差异”PDF 页面:
compare \
-verbose \
-debug coder -log "%u %m:%l %e" \
somewhere/reference_page_001.pdf \
somewhere/comparison_page_001.pdf \
-compose src \
somewhereelse/reference_diff_page_001.pdf
鬼脚本
由于自动插入元数据(例如当前日期+时间),PDF 输出不适用于基于 MD5hash 的文件比较。
如果您想自动发现由纯白页组成的所有案例,您还可以使用bmp256
输出设备转换为无元数据位图格式。您可以对原始 PDF(参考和比较)或 diff-PDF 页面执行此操作:
gs \
-o reference_diff_page_001.bmp \
-r72 \
-g595x842 \
-sDEVICE=bmp256 \
reference_diff_page_001.pdf
md5sum reference_diff_page_001.bmp
如果 MD5sum 是您期望的 595x842 PostScript 点的全白页面,那么您的单元测试通过了。
更新:
我不知道为什么我以前没有想到从 ImageMagick生成直方图compare
输出......
以下是链接 2 个不同命令的命令管道:
- 第一个与上面
compare
生成“白色像素相等,红色像素不同”的格式相同,只是它输出 ImageMagick 内部miff
格式。它不会写入文件,而是写入stdout。 - 第二个用于
convert
读取stdin,生成直方图并以文本形式输出结果。会有两行:- 1 表示白色像素的数量
- 另一个表示红色像素的数量。
它是这样的:
compare \
reference.pdf \
current.pdf \
-compose src \
miff:- \
| \
convert \
- \
-define histogram:unique-colors=true \
-format %c \
histogram:info:-
样本输出:
56934: (61937, 0, 7710,52428) #F1F100001E1ECCCC srgba(241,0,30,0.8)
444056: (65535,65535,65535,52428) #FFFFFFFFFFFFCCCC srgba(255,255,255,0.8)
(示例输出是使用这些reference.pdf和current.pdf文件生成的。)
我认为这种类型的输出非常适合自动单元测试。如果您评估这两个数字,您可以轻松计算“红色像素”百分比,甚至可以根据某个阈值决定返回PASSED或FAILED(如果由于某种原因您不一定需要“零红色”)。
您可以将 PDF 捕获为位图(或至少是无损压缩)图像,然后将每个测试生成的图像与它应该看起来的参考图像进行比较。任何差异都将被标记为测试错误。
我脑海中浮现的第一个想法是使用 diff 实用程序。这些通常用于比较文档的文本,但它们也可以比较 PDF 的布局。使用它,您可以将预期输出与提供的输出进行比较。
谷歌给我的第一个结果是这个。尽管它是商业的,但可能还有其他免费/开源的替代品。
我会尝试使用 xpresser - (https://wiki.ubuntu.com/Xpresser) 您可以尝试将图像匹配到类似图像而不是精确副本 - 这是这些情况下的问题。
我不知道 xpresser 是否正在积极开发,或者它是否可以与独立的图像文件一起使用(我想是的)——无论如何,它的想法来自 teh Sikuli 项目(它是带有 Jython 前端的 Java,而xpresser 是 Python)。
我用 Python 编写了一个工具来验证我雇主文档的 PDF。它能够将单个页面与主图像进行比较。我使用我找到的一个名为swftools的库将页面导出为 PNG,然后使用Python Imaging Library将其与母版进行比较。
相关代码看起来像这样(这不会运行,因为脚本的其他部分有一些依赖项,但你应该明白):
# exporting
gfxpdf = gfx.open("pdf", self.pdfpath)
if os.path.isfile(pngPath):
os.remove(pngPath)
page = gfxpdf.getPage(pagenum)
img = gfx.ImageList()
img.startpage(page.width, page.height)
page.render(img)
img.endpage()
img.save(pngPath)
return os.path.isfile(pngPath)
# comparing
outPng = os.path.join(outpath, pngname)
masterPng = os.path.join(outpath, "_master", pngname)
if os.path.isfile(masterPng):
output = Image.open(outPng).convert("RGB") # discard alpha channel, if any
master = Image.open(masterPng).convert("RGB")
mismatch = any(x[1] for x in ImageChops.difference(output, master).getextrema())