19

我正在编写一个使用 Cairo 图形库输出 PDF 文件的 CAD 应用程序。许多单元测试不需要实际生成 PDF 文件,例如计算对象的预期边界框。但是,我想确保在更改代码后生成的 PDF 文件“看起来”正确。有没有一种自动化的方法来做到这一点?我怎样才能尽可能地自动化?我是否需要目视检查每个生成的 PDF?我怎样才能在不拔头发的情况下解决这个问题?

4

5 回答 5

22

(另请参阅下面的更新!)

我在 Linux 上使用 shell 脚本做同样的事情

  1. ImageMagick 的compare命令
  2. 实用pdftk程序
  3. 鬼脚本(可选)

.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 个不同命令的命令管道:

  1. 第一个与上面compare生成“白色像素相等,红色像素不同”的格式相同,只是它输出 ImageMagick 内部miff格式。它不会写入文件,而是写入stdout
  2. 第二个用于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.pdfcurrent.pdf文件生成的。)

我认为这种类型的输出非常适合自动单元测试。如果您评估这两个数字,您可以轻松计算“红色像素”百分比,甚至可以根据某个阈值决定返回PASSEDFAILED(如果由于某种原因您不一定需要“零红色”)。

于 2011-01-12T23:05:12.257 回答
8

您可以将 PDF 捕获为位图(或至少是无损压缩)图像,然后将每个测试生成的图像与它应该看起来的参考图像进行比较。任何差异都将被标记为测试错误。

于 2011-01-12T19:16:55.750 回答
0

我脑海中浮现的第一个想法是使用 diff 实用程序。这些通常用于比较文档的文本,但它们也可以比较 PDF 的布局。使用它,您可以将预期输出与提供的输出进行比较。

谷歌给我的第一个结果是这个。尽管它是商业的,但可能还有其他免费/开源的替代品。

于 2011-01-12T22:04:28.213 回答
0

我会尝试使用 xpresser - (https://wiki.ubuntu.com/Xpresser) 您可以尝试将图像匹配到类似图像而不是精确副本 - 这是这些情况下的问题。

我不知道 xpresser 是否正在积极开发,或者它是否可以与独立的图像文件一起使用(我想是的)——无论如何,它的想法来自 teh Sikuli 项目(它是带有 Jython 前端的 Java,而xpresser 是 Python)。

于 2011-01-13T02:59:53.247 回答
0

我用 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())
于 2011-07-18T18:34:44.487 回答