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

How to capture image comparison result in Windows batch file, using ImageMagick

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

作为一种变通方法,我尝试使用 magick compare 的输出,它在成功时将“0 (0)”发送到 stderr。然而,在这里我未能将 stderr 捕获到环境变量中,可能是因为某些变量范围问题或遗漏了其他内容。 magick 输出被定向到临时文件,然后用 set /P 加载。通过在 magick 比较之后添加暂停,我可以确认 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 没有任何明显的效果。

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

compare.bat some pdf 1

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

@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
)