如何使用 ImageMagick 在 Windows 批处理文件中捕获图像比较结果

Posted

技术标签:

【中文标题】如何使用 ImageMagick 在 Windows 批处理文件中捕获图像比较结果【英文标题】:How to capture image comparison result in Windows batch file, using ImageMagick 【发布时间】:2020-03-11 17:52:34 【问题描述】:

我正在尝试创建一个 Windows bat 文件以在 Windows 10 上使用 GhostScript 和 ImageMagick 7.0.9 比较两个 PDF 文件。第一步为每个页面创建 PNG 文件,并使用“比较”命令创建 magick.exe(没有单独的compare.exe 在 Windows 上)比较图像。不幸的是,即使图像不匹配,“%errorlevel”仍然为 0。

作为一种解决方法,我尝试使用 magick compare 的输出,它在成功时将“0 (0)”发送到 stderr。但是,在这里我无法将 stderr 捕获到环境变量中,可能是因为某些变量范围问题或缺少其他内容。 magick 输出被定向到临时文件,然后用 set /P 加载。通过在魔术比较之后添加暂停,我可以确认 txt 文件在匹配文件中包含“0 (0)”。 echo %SCRIPTRESULT% 什么也不打印。

set /P SCRIPTRESULT=<result/stdtmp.txt

整个bat文件:

@echo off
@rem we assume the current directory is root folder of the test that is being run
@rem get parameters
setlocal

set JOBNAME=%1
set FILETYPE=%2
set PAGECOUNT=%3
set PAGE=1
set FAILPAGE=1
set SCRIPTRESULT=

@rem create the PNG files for two PDFs in ./result/ and ./result_t/ folders

gswin64 -dSAFER -dBATCH -dNOPAUSE -dQUIET -sDEVICE=png16m -sOutputFile=./result/%JOBNAME%_%FILETYPE%_CURR%%d.png -r200 ./result_t/%JOBNAME%.%FILETYPE%
gswin64 -dSAFER -dBATCH -dNOPAUSE -dQUIET -sDEVICE=png16m -sOutputFile=./result/%JOBNAME%_%FILETYPE%_ORIG%%d.png -r200 ./result/%JOBNAME%.%FILETYPE%

@rem gs produces separate PNG for each PDF or PostScript page and we specify the expected count as parameter to this script

FOR /L %%P IN (1,1,%PAGECOUNT%) do (

  set PAGE=%%P
  rem echo Page %PAGE% of %PAGECOUNT%

  magick compare -metric MAE ./result/%JOBNAME%_%FILETYPE%_CURR%PAGE%.png ./result/%JOBNAME%_%FILETYPE%_ORIG%PAGE%.png ./result/%JOBNAME%_%FILETYPE%_DIFF%PAGE%.png 2> result/stdtmp.txt

  rem Errorlevel in Windows ImageMagick is always 0 so we need to observe sderr instead?
  echo The errorlevel is %errorlevel%

  set /P SCRIPTRESULT=<result/stdtmp.txt

  echo Compare returned %SCRIPTRESULT%

  del /Q .\result\stdtmp.txt
  del /Q ".\result\%JOBNAME%_%FILETYPE%_CURR%PAGE%.png"
  del /Q ".\result\%JOBNAME%_%FILETYPE%_ORIG%PAGE%.png"

  IF "%SCRIPTRESULT%" == "0 (0)" (
    echo Deleting .\result\%JOBNAME%_%FILETYPE%_DIFF%PAGE%.png
    del /Q ".\result\%JOBNAME%_%FILETYPE%_DIFF%PAGE%.png"
  ) ELSE (
    echo Failed at page %PAGE%
    set /A FAILPAGE=%PAGE%
  )
)

echo Outside the loop SCRIPTRESULT=%SCRIPTRESULT%

IF "%SCRIPTRESULT%" == "0 (0)" (
  echo Files compare OK  >&2
  )

IF NOT "%SCRIPTRESULT%" == "0 (0)" (
  echo Visual compare failed, see ./result/%JOBNAME%_%FILETYPE%_DIFF%FAILPAGE%.png >&2
)

这个脚本可以运行为

compare.bat filename pdf 1

这假设我们有 .\result\filename.pdf 和 .\result_t\filename.pdf,每个都有 1 页。更复杂的是,此比较脚本旨在通过来自另一个脚本的调用来使用。在那种情况下,我会看到输出:

The errorlevel is 0
Compare returned
Fail at page 1
Outside the loop SCRIPTRESULT=0 (0)
Files compare OK

显然循环外的 SCRIPTRESULT 的值是“0 (0)”,正如预期的那样,但不在 FOR 循环内?添加 setlocal ENABLEDELAYEDEXPANSION 没有任何明显效果。

【问题讨论】:

您可以使用此处的第二个答案将 stderr 捕获到变量中:***.com/questions/29740883/… 您需要延迟变量扩展才能使用代码块内变量的更改值。在 for 循环中,您需要使用 !SCRIPTRESULT! 而不是 %SCRIPTRESULT% 您还需要!PAGE!,否则无论页数如何,您都只会比较第 1 页。虽然你可以改用%%P 哦,对了——%ERRORLEVEL% 也是如此。您可以查看!ERRORLEVEL! 是否有效,或者只使用内置的if errorlevel 1 逻辑。 与其读入stdtmp.txt的内容,不如直接用FINDSTR看看有没有你想要的…… 【参考方案1】:

发布脚本的功能版本,感谢评论者。假设有两个单页 PDF 文件 .\result\some.pdf 和 .\result_t\some.pdf,运行比较:

compare.bat some pdf 1

它也适用于 PostScript 或 GhostScript 可以呈现的任何其他内容。匹配失败将在“结果”文件夹中留下一个视觉差异文件。

@rem we assume the current directory is root folder of the test that is being run
@echo off
@setlocal ENABLEDELAYEDEXPANSION

set JOBNAME=%1
set FILETYPE=%2
set PAGECOUNT=%3
set FAILPAGE=0

@rem Using either pngalpha or png16m device

gswin64 -dSAFER -dBATCH -dNOPAUSE -dQUIET -sDEVICE=png16m -sOutputFile=./result/%JOBNAME%_%FILETYPE%_CURR%%d.png -r200 ./result_t/%JOBNAME%.%FILETYPE%
gswin64 -dSAFER -dBATCH -dNOPAUSE -dQUIET -sDEVICE=png16m -sOutputFile=./result/%JOBNAME%_%FILETYPE%_ORIG%%d.png -r200 ./result/%JOBNAME%.%FILETYPE%

@rem gs produces separate PNG for each PDF or PostScript page and we specify the expected count as parameter to this script
@rem Note that we do not catch case where the result has more pages than template

FOR /L %%P IN (1,1,%PAGECOUNT%) do (

  magick compare -metric MAE "./result/%JOBNAME%_%FILETYPE%_CURR%%P.png" "./result/%JOBNAME%_%FILETYPE%_ORIG%%P.png" "./result/%JOBNAME%_%FILETYPE%_DIFF%%P.png" 2>nul

  rem echo The errorlevel is !errorlevel!

  IF !errorlevel! == 0 (
    del /Q ".\result\%JOBNAME%_!FILETYPE!_DIFF%%P.png"
  ) ELSE (
    echo Difference on page %%P
    set /A FAILPAGE=%%P
  )

  del /Q ".\result\%JOBNAME%_!FILETYPE!_CURR%%P.png"
  del /Q ".\result\%JOBNAME%_!FILETYPE!_ORIG%%P.png"
)

IF  !FAILPAGE! == 0 (
  echo Files compare OK >&2
  EXIT /B 0
  ) else (
  echo Visual compare failed, see ./result/%JOBNAME%_!FILETYPE!_DIFF!FAILPAGE!.png >&2
  EXIT /B 1
)

【讨论】:

以上是关于如何使用 ImageMagick 在 Windows 批处理文件中捕获图像比较结果的主要内容,如果未能解决你的问题,请参考以下文章

如何使用自制软件安装 imagemagick?

Window安装Imagick扩展及配置

我应该将哪些文件复制到我的项目中以使用 ImageMagick?或如何在 Windows 上使用 MinGW 编译 ImageMagick?

ImageMagick:如何在没有背景的情况下使用 mogrify 按比例调整大小

如何在 Windows 7 上安装 ImageMagick 以与 PHP 一起使用 (3)

Window10安装Imagick扩展及配置