@@ -45,8 +45,9 @@ This file is part of the iText (R) project.
4545
4646import com .itextpdf .io .IoExceptionMessage ;
4747
48- import java .io .File ;
4948import java .io .IOException ;
49+ import java .util .regex .Matcher ;
50+ import java .util .regex .Pattern ;
5051
5152/**
5253 * A utility class that is used as an interface to run 3rd-party tool ImageMagick.
@@ -69,6 +70,9 @@ public class ImageMagickHelper {
6970 static final String MAGICK_COMPARE_KEYWORD = "ImageMagick Studio LLC" ;
7071
7172 private static final String TEMP_FILE_PREFIX = "itext_im_io_temp" ;
73+ private static final String DIFF_PIXELS_OUTPUT_REGEXP = "^\\ d+\\ .*\\ d*(e\\ +\\ d+)?" ;
74+
75+ private static final Pattern pattern = Pattern .compile (DIFF_PIXELS_OUTPUT_REGEXP );
7276
7377 private String compareExec ;
7478
@@ -139,6 +143,58 @@ public boolean runImageMagickImageCompare(String outImageFilePath, String cmpIma
139143 */
140144 public boolean runImageMagickImageCompare (String outImageFilePath , String cmpImageFilePath ,
141145 String diffImageName , String fuzzValue ) throws IOException , InterruptedException {
146+ ImageMagickCompareResult compareResult = runImageMagickImageCompareAndGetResult (outImageFilePath ,
147+ cmpImageFilePath , diffImageName , fuzzValue );
148+
149+ return compareResult .isComparingResultSuccessful ();
150+ }
151+
152+ /**
153+ * Runs imageMagick to visually compare images with the specified fuzziness value and given threshold
154+ * and generate difference output.
155+ *
156+ * @param outImageFilePath Path to the output image file
157+ * @param cmpImageFilePath Path to the cmp image file
158+ * @param diffImageName Path to the difference output image file
159+ * @param fuzzValue String fuzziness value to compare images. Should be formatted as string with integer
160+ * or decimal number. Can be null, if it is not required to use fuzziness
161+ * @param threshold Long value of accepted threshold.
162+ *
163+ * @return boolean result of comparing: true - images are visually equal
164+ *
165+ * @throws IOException if there are file's reading/writing issues
166+ * @throws InterruptedException if there is thread interruption while executing ImageMagick.
167+ */
168+ public boolean runImageMagickImageCompareWithThreshold (String outImageFilePath , String cmpImageFilePath ,
169+ String diffImageName , String fuzzValue , long threshold ) throws IOException , InterruptedException {
170+ ImageMagickCompareResult compareResult = runImageMagickImageCompareAndGetResult (outImageFilePath ,
171+ cmpImageFilePath , diffImageName , fuzzValue );
172+
173+ if (compareResult .isComparingResultSuccessful ()) {
174+ return true ;
175+ } else {
176+ return compareResult .getDiffPixels () <= threshold ;
177+ }
178+ }
179+
180+ /**
181+ * Runs imageMagick to visually compare images with the specified fuzziness value and generate difference output.
182+ * This method returns an object of {@link ImageMagickCompareResult}, containing comparing result information,
183+ * such as boolean result value and the number of different pixels.
184+ *
185+ * @param outImageFilePath Path to the output image file
186+ * @param cmpImageFilePath Path to the cmp image file
187+ * @param diffImageName Path to the difference output image file
188+ * @param fuzzValue String fuzziness value to compare images. Should be formatted as string with integer
189+ * or decimal number. Can be null, if it is not required to use fuzziness
190+ *
191+ * @return an object of {@link ImageMagickCompareResult}. containing comparing result information.
192+ *
193+ * @throws IOException if there are file's reading/writing issues
194+ * @throws InterruptedException if there is thread interruption while executing ImageMagick.
195+ */
196+ public ImageMagickCompareResult runImageMagickImageCompareAndGetResult (String outImageFilePath ,
197+ String cmpImageFilePath , String diffImageName , String fuzzValue ) throws IOException , InterruptedException {
142198 if (!validateFuzziness (fuzzValue )) {
143199 throw new IllegalArgumentException ("Invalid fuzziness value: " + fuzzValue );
144200 }
@@ -158,12 +214,15 @@ public boolean runImageMagickImageCompare(String outImageFilePath, String cmpIma
158214 + replacementOutFile + "' '"
159215 + replacementCmpFile + "' '"
160216 + replacementDiff + "'" ;
161- boolean result = SystemUtil .runProcessAndWait (compareExec , currCompareParams );
217+ ProcessInfo processInfo = SystemUtil .runProcessAndGetProcessInfo (compareExec , currCompareParams );
218+ boolean comparingResult = processInfo .getExitCode () == 0 ;
219+ long diffPixels = parseImageMagickProcessOutput (processInfo .getProcessErrOutput ());
220+ ImageMagickCompareResult resultInfo = new ImageMagickCompareResult (comparingResult , diffPixels );
162221
163222 if (FileUtil .fileExists (replacementDiff )) {
164223 FileUtil .copy (replacementDiff , diffImageName );
165224 }
166- return result ;
225+ return resultInfo ;
167226 } finally {
168227 FileUtil .removeFiles (new String [] {replacementOutFile , replacementCmpFile , replacementDiff });
169228 }
@@ -182,4 +241,29 @@ static boolean validateFuzziness(String fuzziness) {
182241 }
183242 }
184243 }
244+
245+ private static long parseImageMagickProcessOutput (String processOutput ) throws IOException {
246+ if (null == processOutput ) {
247+ throw new IllegalArgumentException (IoExceptionMessage .IMAGE_MAGICK_OUTPUT_IS_NULL );
248+ }
249+
250+ if (processOutput .isEmpty ()) {
251+ return 0L ;
252+ }
253+
254+ String [] processOutputLines = processOutput .split ("\n " );
255+
256+ for (String line : processOutputLines ) {
257+ try {
258+ Matcher matcher = pattern .matcher (line );
259+ if (matcher .find ()) {
260+ return (long ) Double .valueOf (matcher .group ()).longValue ();
261+ }
262+ } catch (NumberFormatException e ) {
263+ // Nothing should be done here because of the exception, that will be thrown later.
264+ }
265+ }
266+
267+ throw new IOException (IoExceptionMessage .IMAGE_MAGICK_PROCESS_EXECUTION_FAILED + processOutput );
268+ }
185269}
0 commit comments