Я пишу приложение САПР, которое выводит файлы PDF с использованием графической библиотеки Cairo. Большая часть модульного тестирования не требует фактически создания файлов PDF, таких как вычисление ожидаемых ограничивающих прямоугольников объектов. Тем не менее, я хочу убедиться, что сгенерированные PDF файлы выглядят корректно после изменения кода. Есть ли автоматизированный способ сделать это? Как я могу автоматизировать как можно больше? Нужно ли мне визуально проверять каждый сгенерированный PDF файл? Как я могу решить эту проблему, не вытаскивая волосы?
Как unit test функция Python, которая рисует графику PDF?
Ответ 1
Вы можете захватить PDF в виде растрового изображения (или, по крайней мере, без потерь), а затем сравнить образ, сгенерированный каждым тестом, с образцом ссылки на то, как он должен выглядеть. Любые различия будут помечены как ошибка для теста.
Ответ 2
(См. также обновление ниже!)
Я делаю то же самое, используя оболочку script в Linux, которая обертывает
- Команда ImageMagick
compare
- утилита
pdftk
- Ghostscript (необязательно)
(Было бы довольно легко переносить это в пакетный файл .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
<сравнения/h2 >
Используйте эту команду для создания страницы "diff" 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 не работает хорошо для сравнения файлов на основе 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 - это то, что вы ожидаете от всей белой страницы точек PostScript 595x842, то ваш unit test прошел.
Update:
Я не знаю, почему я раньше не думал о генерации вывода гистограммы из ImageMagick compare
...
Ниже приведена цепочка команд, связывающая две разные команды:
- первая такая же, как приведенная выше
compare
, которая генерирует "белые пиксели равны, красные пиксели являются отличительными", только он выводит внутренний форматmiff
ImageMagick. Он не записывается в файл, а в стандартный вывод. - второй использует
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.pdf и current.pdf.
Я думаю, что этот тип вывода действительно хорошо подходит для автоматического модульного тестирования. Если вы оцениваете два числа, вы можете легко вычислить процент "красного пикселя", и вы даже можете принять решение о возврате PASSED или FAILED на основе определенного порога (если по какой-то причине вам необязательно нужен "нулевой красный цвет" ).
Ответ 3
Первая идея, которая появляется у меня в голове, - использовать утилиту diff. Они обычно используются для сравнения текстов документов, но они также могут сравнивать макет PDF. Используя его, вы можете сравнить ожидаемый результат с поставляемым выходом.
Первый результат google дает мне this. Хотя это коммерчески, могут быть и другие альтернативы с открытым/открытым исходным кодом.
Ответ 4
Я бы попробовал это с помощью xpresser - (https://wiki.ubuntu.com/Xpresser). Вы можете попытаться совместить изображения с похожими изображениями, а не точные копии, что является проблемой в этих случаях.
Я не знаю, развивается ли xpresser, или если он может использоваться с автономными файлами изображений (я так думаю) - в любом случае он берет свои идеи из проекта Sikuli (который является Java с фронтом Jython end, а xpresser - Python).
Ответ 5
Я написал инструмент в Python для проверки PDF файлов для документации моего работодателя. Он имеет возможность сравнивать отдельные страницы с основными изображениями. Я использовал найденную мной библиотеку swftools для экспорта страницы в PNG, затем использовал Python Imaging Library, чтобы сравнить его с мастером.
Соответствующий код выглядит примерно так (это не будет работать, так как есть некоторые зависимости от других частей script, но вы должны получить идею):
# 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())