如何对绘制PDF图形的Python函数进行单元测试?

21 投票
7 回答
6313 浏览
提问于 2025-04-16 09:51

我正在开发一个CAD应用程序,它使用Cairo图形库来输出PDF文件。很多单元测试其实并不需要真的生成PDF文件,比如计算对象的预期边界框。不过,我想确保在我修改代码后,生成的PDF文件“看起来”是正确的。有没有什么自动化的方法可以做到这一点?我该如何尽可能地自动化这个过程?我需要逐个检查每个生成的PDF吗?我该如何解决这个问题,才能不抓狂呢?

7 个回答

0

我建议你试试xpresser这个工具 - (https://wiki.ubuntu.com/Xpresser)。这个工具可以帮助你找到相似的图片,而不是完全相同的图片,这正是这些情况下遇到的问题。

我不太确定xpresser是否还在积极开发中,或者它是否可以和独立的图片文件一起使用(我觉得可以)——总之,它的灵感来源于Sikuli项目(Sikuli是用Java写的,前端用的是Jython,而xpresser是用Python写的)。

24

(请查看下面的更新!)

我在Linux上用一个shell脚本做同样的事情,这个脚本包含了:

  1. ImageMagick的compare命令
  2. pdftk工具
  3. Ghostscript(可选)

把这个移植到DOS/Windows的.bat批处理文件也很简单。

我有一些由我的应用程序生成的参考PDF,这些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

compare

使用这个命令为每一页创建一个“差异”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

Ghostscript

由于自动插入的元数据(比如当前的日期和时间),PDF输出在基于MD5哈希的文件比较中效果不好。

如果你想自动发现所有纯白页面的情况,可以使用bmp256输出设备转换为没有元数据的位图格式。你可以对原始PDF(参考和比较)或差异PDF页面进行这样的转换:

 gs \
   -o reference_diff_page_001.bmp \
   -r72 \
   -g595x842 \
   -sDEVICE=bmp256 \
    reference_diff_page_001.pdf

 md5sum reference_diff_page_001.bmp
 

如果MD5值符合你对一个595x842 PostScript点的全白页面的预期,那么你的单元测试就通过了。


更新:

我不知道之前为什么没想到从ImageMagick的compare生成一个直方图输出...

以下是一个命令管道,连接了两个不同的命令:

  1. 第一个命令和上面的compare一样,生成'白色像素相等,红色像素为差异'格式,只是它输出的是ImageMagick内部的miff格式。它不会写入文件,而是输出到stdout
  2. 第二个命令使用convert读取stdin,生成直方图并以文本形式输出结果。会有两行:
    • 一行表示白色像素的数量
    • 另一行表示红色像素的数量。

下面是命令:

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(如果你出于某种原因不一定需要“零红色”)。

8

你可以把PDF文件转换成一种叫做位图的图片格式(或者至少是无损压缩的图片),然后把每次测试生成的图片和一个标准的参考图片进行对比。只要有任何不同的地方,就会被标记为测试错误。

撰写回答