@@ -44,11 +44,13 @@ This file is part of the iText (R) project.
4444package com .itextpdf .io .util ;
4545
4646import com .itextpdf .commons .utils .FileUtil ;
47+ import com .itextpdf .commons .utils .ProcessInfo ;
4748import com .itextpdf .commons .utils .SystemUtil ;
4849import com .itextpdf .io .exceptions .IoExceptionMessage ;
4950
50- import java .io .File ;
5151import java .io .IOException ;
52+ import java .util .regex .Matcher ;
53+ import java .util .regex .Pattern ;
5254
5355/**
5456 * A utility class that is used as an interface to run 3rd-party tool ImageMagick.
@@ -71,6 +73,9 @@ public class ImageMagickHelper {
7173 static final String MAGICK_COMPARE_KEYWORD = "ImageMagick Studio LLC" ;
7274
7375 private static final String TEMP_FILE_PREFIX = "itext_im_io_temp" ;
76+ private static final String DIFF_PIXELS_OUTPUT_REGEXP = "^\\ d+\\ .*\\ d*(e\\ +\\ d+)?" ;
77+
78+ private static final Pattern pattern = Pattern .compile (DIFF_PIXELS_OUTPUT_REGEXP );
7479
7580 private String compareExec ;
7681
@@ -141,6 +146,58 @@ public boolean runImageMagickImageCompare(String outImageFilePath, String cmpIma
141146 */
142147 public boolean runImageMagickImageCompare (String outImageFilePath , String cmpImageFilePath ,
143148 String diffImageName , String fuzzValue ) throws IOException , InterruptedException {
149+ ImageMagickCompareResult compareResult = runImageMagickImageCompareAndGetResult (outImageFilePath ,
150+ cmpImageFilePath , diffImageName , fuzzValue );
151+
152+ return compareResult .isComparingResultSuccessful ();
153+ }
154+
155+ /**
156+ * Runs imageMagick to visually compare images with the specified fuzziness value and given threshold
157+ * and generate difference output.
158+ *
159+ * @param outImageFilePath Path to the output image file
160+ * @param cmpImageFilePath Path to the cmp image file
161+ * @param diffImageName Path to the difference output image file
162+ * @param fuzzValue String fuzziness value to compare images. Should be formatted as string with integer
163+ * or decimal number. Can be null, if it is not required to use fuzziness
164+ * @param threshold Long value of accepted threshold.
165+ *
166+ * @return boolean result of comparing: true - images are visually equal
167+ *
168+ * @throws IOException if there are file's reading/writing issues
169+ * @throws InterruptedException if there is thread interruption while executing ImageMagick.
170+ */
171+ public boolean runImageMagickImageCompareWithThreshold (String outImageFilePath , String cmpImageFilePath ,
172+ String diffImageName , String fuzzValue , long threshold ) throws IOException , InterruptedException {
173+ ImageMagickCompareResult compareResult = runImageMagickImageCompareAndGetResult (outImageFilePath ,
174+ cmpImageFilePath , diffImageName , fuzzValue );
175+
176+ if (compareResult .isComparingResultSuccessful ()) {
177+ return true ;
178+ } else {
179+ return compareResult .getDiffPixels () <= threshold ;
180+ }
181+ }
182+
183+ /**
184+ * Runs imageMagick to visually compare images with the specified fuzziness value and generate difference output.
185+ * This method returns an object of {@link ImageMagickCompareResult}, containing comparing result information,
186+ * such as boolean result value and the number of different pixels.
187+ *
188+ * @param outImageFilePath Path to the output image file
189+ * @param cmpImageFilePath Path to the cmp image file
190+ * @param diffImageName Path to the difference output image file
191+ * @param fuzzValue String fuzziness value to compare images. Should be formatted as string with integer
192+ * or decimal number. Can be null, if it is not required to use fuzziness
193+ *
194+ * @return an object of {@link ImageMagickCompareResult}. containing comparing result information.
195+ *
196+ * @throws IOException if there are file's reading/writing issues
197+ * @throws InterruptedException if there is thread interruption while executing ImageMagick.
198+ */
199+ public ImageMagickCompareResult runImageMagickImageCompareAndGetResult (String outImageFilePath ,
200+ String cmpImageFilePath , String diffImageName , String fuzzValue ) throws IOException , InterruptedException {
144201 if (!validateFuzziness (fuzzValue )) {
145202 throw new IllegalArgumentException ("Invalid fuzziness value: " + fuzzValue );
146203 }
@@ -160,12 +217,15 @@ public boolean runImageMagickImageCompare(String outImageFilePath, String cmpIma
160217 + replacementOutFile + "' '"
161218 + replacementCmpFile + "' '"
162219 + replacementDiff + "'" ;
163- boolean result = SystemUtil .runProcessAndWait (compareExec , currCompareParams );
220+ ProcessInfo processInfo = SystemUtil .runProcessAndGetProcessInfo (compareExec , currCompareParams );
221+ boolean comparingResult = processInfo .getExitCode () == 0 ;
222+ long diffPixels = parseImageMagickProcessOutput (processInfo .getProcessErrOutput ());
223+ ImageMagickCompareResult resultInfo = new ImageMagickCompareResult (comparingResult , diffPixels );
164224
165225 if (FileUtil .fileExists (replacementDiff )) {
166226 FileUtil .copy (replacementDiff , diffImageName );
167227 }
168- return result ;
228+ return resultInfo ;
169229 } finally {
170230 FileUtil .removeFiles (new String [] {replacementOutFile , replacementCmpFile , replacementDiff });
171231 }
@@ -184,4 +244,29 @@ static boolean validateFuzziness(String fuzziness) {
184244 }
185245 }
186246 }
247+
248+ private static long parseImageMagickProcessOutput (String processOutput ) throws IOException {
249+ if (null == processOutput ) {
250+ throw new IllegalArgumentException (IoExceptionMessage .IMAGE_MAGICK_OUTPUT_IS_NULL );
251+ }
252+
253+ if (processOutput .isEmpty ()) {
254+ return 0L ;
255+ }
256+
257+ String [] processOutputLines = processOutput .split ("\n " );
258+
259+ for (String line : processOutputLines ) {
260+ try {
261+ Matcher matcher = pattern .matcher (line );
262+ if (matcher .find ()) {
263+ return (long ) Double .valueOf (matcher .group ()).longValue ();
264+ }
265+ } catch (NumberFormatException e ) {
266+ // Nothing should be done here because of the exception, that will be thrown later.
267+ }
268+ }
269+
270+ throw new IOException (IoExceptionMessage .IMAGE_MAGICK_PROCESS_EXECUTION_FAILED + processOutput );
271+ }
187272}
0 commit comments