MagickWand  7.0.9
compare.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % CCCC OOO M M PPPP AAA RRRR EEEEE %
7 % C O O MM MM P P A A R R E %
8 % C O O M M M PPPP AAAAA RRRR EEE %
9 % C O O M M P A A R R E %
10 % CCCC OOO M M P A A R R EEEEE %
11 % %
12 % %
13 % Image Comparison Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % December 2003 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 % Use the compare program to mathematically and visually annotate the
37 % difference between an image and its reconstruction.
38 %
39 */
40 
41 /*
42  Include declarations.
43 */
44 #include "MagickWand/studio.h"
45 #include "MagickWand/MagickWand.h"
47 #include "MagickCore/string-private.h"
48 
49 /*
50 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
51 % %
52 % %
53 % %
54 % C o m p a r e I m a g e C o m m a n d %
55 % %
56 % %
57 % %
58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59 %
60 % CompareImagesCommand() compares two images and returns the difference between
61 % them as a distortion metric and as a new image visually annotating their
62 % differences.
63 %
64 % The format of the CompareImagesCommand method is:
65 %
66 % MagickBooleanType CompareImagesCommand(ImageInfo *image_info,int argc,
67 % char **argv,char **metadata,ExceptionInfo *exception)
68 %
69 % A description of each parameter follows:
70 %
71 % o image_info: the image info.
72 %
73 % o argc: the number of elements in the argument vector.
74 %
75 % o argv: A text array containing the command line arguments.
76 %
77 % o metadata: any metadata is returned here.
78 %
79 % o exception: return any errors or warnings in this structure.
80 %
81 */
82 
83 static MagickBooleanType CompareUsage(void)
84 {
85  static const char
86  channel_operators[] =
87  " -separate separate an image channel into a grayscale image",
88  miscellaneous[] =
89  " -channel mask set the image channel mask\n"
90  " -debug events display copious debugging information\n"
91  " -help print program options\n"
92  " -list type print a list of supported option arguments\n"
93  " -log format format of debugging information",
94  operators[] =
95  " -brightness-contrast geometry\n"
96  " improve brightness / contrast of the image\n"
97  " -distort method args\n"
98  " distort images according to given method and args\n"
99  " -level value adjust the level of image contrast\n"
100  " -resize geometry resize the image\n"
101  " -rotate degrees apply Paeth rotation to the image\n"
102  " -sigmoidal-contrast geometry\n"
103  " increase the contrast without saturating highlights or\n"
104  " -trim trim image edges\n"
105  " -write filename write images to this file",
106  sequence_operators[] =
107  " -crop geometry cut out a rectangular region of the image",
108  settings[] =
109  " -alpha option on, activate, off, deactivate, set, opaque, copy\n"
110  " transparent, extract, background, or shape\n"
111  " -authenticate password\n"
112  " decipher image with this password\n"
113  " -background color background color\n"
114  " -colorspace type alternate image colorspace\n"
115  " -compose operator set image composite operator\n"
116  " -compress type type of pixel compression when writing the image\n"
117  " -decipher filename convert cipher pixels to plain pixels\n"
118  " -define format:option\n"
119  " define one or more image format options\n"
120  " -density geometry horizontal and vertical density of the image\n"
121  " -depth value image depth\n"
122  " -dissimilarity-threshold value\n"
123  " maximum distortion for (sub)image match\n"
124  " -encipher filename convert plain pixels to cipher pixels\n"
125  " -extract geometry extract area from image\n"
126  " -format \"string\" output formatted image characteristics\n"
127  " -fuzz distance colors within this distance are considered equal\n"
128  " -gravity type horizontal and vertical text placement\n"
129  " -highlight-color color\n"
130  " empasize pixel differences with this color\n"
131  " -identify identify the format and characteristics of the image\n"
132  " -interlace type type of image interlacing scheme\n"
133  " -limit type value pixel cache resource limit\n"
134  " -lowlight-color color\n"
135  " de-emphasize pixel differences with this color\n"
136  " -metric type measure differences between images with this metric\n"
137  " -monitor monitor progress\n"
138  " -negate replace every pixel with its complementary color \n"
139  " -passphrase filename get the passphrase from this file\n"
140  " -precision value maximum number of significant digits to print\n"
141  " -profile filename add, delete, or apply an image profile\n"
142  " -quality value JPEG/MIFF/PNG compression level\n"
143  " -quiet suppress all warning messages\n"
144  " -quantize colorspace reduce colors in this colorspace\n"
145  " -read-mask filename associate a read mask with the image\n"
146  " -regard-warnings pay attention to warning messages\n"
147  " -respect-parentheses settings remain in effect until parenthesis boundary\n"
148  " -sampling-factor geometry\n"
149  " horizontal and vertical sampling factor\n"
150  " -seed value seed a new sequence of pseudo-random numbers\n"
151  " -set attribute value set an image attribute\n"
152  " -quality value JPEG/MIFF/PNG compression level\n"
153  " -repage geometry size and location of an image canvas\n"
154  " -similarity-threshold value\n"
155  " minimum distortion for (sub)image match\n"
156  " -size geometry width and height of image\n"
157  " -subimage-search search for subimage\n"
158  " -synchronize synchronize image to storage device\n"
159  " -taint declare the image as modified\n"
160  " -transparent-color color\n"
161  " transparent color\n"
162  " -type type image type\n"
163  " -verbose print detailed information about the image\n"
164  " -version print version information\n"
165  " -virtual-pixel method\n"
166  " virtual pixel access method\n"
167  " -write-mask filename associate a write mask with the image",
168  stack_operators[] =
169  " -delete indexes delete the image from the image sequence";
170 
171  ListMagickVersion(stdout);
172  (void) printf("Usage: %s [options ...] image reconstruct difference\n",
173  GetClientName());
174  (void) printf("\nImage Settings:\n");
175  (void) puts(settings);
176  (void) printf("\nImage Operators:\n");
177  (void) puts(operators);
178  (void) printf("\nImage Channel Operators:\n");
179  (void) puts(channel_operators);
180  (void) printf("\nImage Sequence Operators:\n");
181  (void) puts(sequence_operators);
182  (void) printf("\nImage Stack Operators:\n");
183  (void) puts(stack_operators);
184  (void) printf("\nMiscellaneous Options:\n");
185  (void) puts(miscellaneous);
186  (void) printf(
187  "\nBy default, the image format of 'file' is determined by its magic\n");
188  (void) printf(
189  "number. To specify a particular image format, precede the filename\n");
190  (void) printf(
191  "with an image format name and a colon (i.e. ps:image) or specify the\n");
192  (void) printf(
193  "image type as the filename suffix (i.e. image.ps). Specify 'file' as\n");
194  (void) printf("'-' for standard input or output.\n");
195  return(MagickFalse);
196 }
197 
198 WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info,
199  int argc,char **argv,char **metadata,ExceptionInfo *exception)
200 {
201 #define CompareEpsilon (1.0e-06)
202 #define DefaultDissimilarityThreshold 0.31830988618379067154
203 #define DefaultSimilarityThreshold (-1.0)
204 #define DestroyCompare() \
205 { \
206  if (similarity_image != (Image *) NULL) \
207  similarity_image=DestroyImageList(similarity_image); \
208  if (difference_image != (Image *) NULL) \
209  difference_image=DestroyImageList(difference_image); \
210  DestroyImageStack(); \
211  for (i=0; i < (ssize_t) argc; i++) \
212  argv[i]=DestroyString(argv[i]); \
213  argv=(char **) RelinquishMagickMemory(argv); \
214 }
215 #define ThrowCompareException(asperity,tag,option) \
216 { \
217  if (exception->severity < (asperity)) \
218  (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
219  "`%s'",option); \
220  DestroyCompare(); \
221  return(MagickFalse); \
222 }
223 #define ThrowCompareInvalidArgumentException(option,argument) \
224 { \
225  (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
226  "InvalidArgument","'%s': %s",option,argument); \
227  DestroyCompare(); \
228  return(MagickFalse); \
229 }
230 
231  char
232  *filename,
233  *option;
234 
235  const char
236  *format;
237 
238  double
239  dissimilarity_threshold,
240  distortion,
241  similarity_metric,
242  similarity_threshold;
243 
244  Image
245  *difference_image,
246  *image,
247  *reconstruct_image,
248  *similarity_image;
249 
250  ImageStack
251  image_stack[MaxImageStackDepth+1];
252 
253  MagickBooleanType
254  fire,
255  pend,
256  respect_parenthesis,
257  subimage_search;
258 
259  MagickStatusType
260  status;
261 
262  MetricType
263  metric;
264 
265  RectangleInfo
266  offset;
267 
268  register ssize_t
269  i;
270 
271  ssize_t
272  j,
273  k;
274 
275  /*
276  Set defaults.
277  */
278  assert(image_info != (ImageInfo *) NULL);
279  assert(image_info->signature == MagickCoreSignature);
280  if (image_info->debug != MagickFalse)
281  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
282  assert(exception != (ExceptionInfo *) NULL);
283  if (argc == 2)
284  {
285  option=argv[1];
286  if ((LocaleCompare("version",option+1) == 0) ||
287  (LocaleCompare("-version",option+1) == 0))
288  {
289  ListMagickVersion(stdout);
290  return(MagickTrue);
291  }
292  }
293  if (argc < 3)
294  return(CompareUsage());
295  difference_image=NewImageList();
296  similarity_image=NewImageList();
297  dissimilarity_threshold=DefaultDissimilarityThreshold;
298  similarity_threshold=DefaultSimilarityThreshold;
299  distortion=0.0;
300  format=(char *) NULL;
301  j=1;
302  k=0;
303  metric=UndefinedErrorMetric;
304  NewImageStack();
305  option=(char *) NULL;
306  pend=MagickFalse;
307  reconstruct_image=NewImageList();
308  respect_parenthesis=MagickFalse;
309  status=MagickTrue;
310  subimage_search=MagickFalse;
311  /*
312  Compare an image.
313  */
314  ReadCommandlLine(argc,&argv);
315  status=ExpandFilenames(&argc,&argv);
316  if (status == MagickFalse)
317  ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
318  GetExceptionMessage(errno));
319  for (i=1; i < (ssize_t) (argc-1); i++)
320  {
321  option=argv[i];
322  if (LocaleCompare(option,"(") == 0)
323  {
324  FireImageStack(MagickTrue,MagickTrue,pend);
325  if (k == MaxImageStackDepth)
326  ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply",
327  option);
328  PushImageStack();
329  continue;
330  }
331  if (LocaleCompare(option,")") == 0)
332  {
333  FireImageStack(MagickTrue,MagickTrue,MagickTrue);
334  if (k == 0)
335  ThrowCompareException(OptionError,"UnableToParseExpression",option);
336  PopImageStack();
337  continue;
338  }
339  if (IsCommandOption(option) == MagickFalse)
340  {
341  Image
342  *images;
343 
344  /*
345  Read input image.
346  */
347  FireImageStack(MagickFalse,MagickFalse,pend);
348  filename=argv[i];
349  if ((LocaleCompare(filename,"--") == 0) && (i < (ssize_t) (argc-1)))
350  filename=argv[++i];
351  images=ReadImages(image_info,filename,exception);
352  status&=(images != (Image *) NULL) &&
353  (exception->severity < ErrorException);
354  if (images == (Image *) NULL)
355  continue;
356  AppendImageStack(images);
357  continue;
358  }
359  pend=image != (Image *) NULL ? MagickTrue : MagickFalse;
360  switch (*(option+1))
361  {
362  case 'a':
363  {
364  if (LocaleCompare("alpha",option+1) == 0)
365  {
366  ssize_t
367  type;
368 
369  if (*option == '+')
370  break;
371  i++;
372  if (i == (ssize_t) argc)
373  ThrowCompareException(OptionError,"MissingArgument",option);
374  type=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,
375  argv[i]);
376  if (type < 0)
377  ThrowCompareException(OptionError,
378  "UnrecognizedAlphaChannelOption",argv[i]);
379  break;
380  }
381  if (LocaleCompare("authenticate",option+1) == 0)
382  {
383  if (*option == '+')
384  break;
385  i++;
386  if (i == (ssize_t) argc)
387  ThrowCompareException(OptionError,"MissingArgument",option);
388  break;
389  }
390  ThrowCompareException(OptionError,"UnrecognizedOption",option);
391  }
392  case 'b':
393  {
394  if (LocaleCompare("background",option+1) == 0)
395  {
396  if (*option == '+')
397  break;
398  i++;
399  if (i == (ssize_t) argc)
400  ThrowCompareException(OptionError,"MissingArgument",option);
401  break;
402  }
403  if (LocaleCompare("brightness-contrast",option+1) == 0)
404  {
405  i++;
406  if (i == (ssize_t) argc)
407  ThrowCompareException(OptionError,"MissingArgument",option);
408  if (IsGeometry(argv[i]) == MagickFalse)
409  ThrowCompareInvalidArgumentException(option,argv[i]);
410  break;
411  }
412  ThrowCompareException(OptionError,"UnrecognizedOption",option);
413  }
414  case 'c':
415  {
416  if (LocaleCompare("cache",option+1) == 0)
417  {
418  if (*option == '+')
419  break;
420  i++;
421  if (i == (ssize_t) argc)
422  ThrowCompareException(OptionError,"MissingArgument",option);
423  if (IsGeometry(argv[i]) == MagickFalse)
424  ThrowCompareInvalidArgumentException(option,argv[i]);
425  break;
426  }
427  if (LocaleCompare("channel",option+1) == 0)
428  {
429  ssize_t
430  channel;
431 
432  if (*option == '+')
433  break;
434  i++;
435  if (i == (ssize_t) argc)
436  ThrowCompareException(OptionError,"MissingArgument",option);
437  channel=ParseChannelOption(argv[i]);
438  if (channel < 0)
439  ThrowCompareException(OptionError,"UnrecognizedChannelType",
440  argv[i]);
441  break;
442  }
443  if (LocaleCompare("colorspace",option+1) == 0)
444  {
445  ssize_t
446  colorspace;
447 
448  if (*option == '+')
449  break;
450  i++;
451  if (i == (ssize_t) argc)
452  ThrowCompareException(OptionError,"MissingArgument",option);
453  colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,
454  argv[i]);
455  if (colorspace < 0)
456  ThrowCompareException(OptionError,"UnrecognizedColorspace",
457  argv[i]);
458  break;
459  }
460  if (LocaleCompare("compose",option+1) == 0)
461  {
462  ssize_t
463  compose;
464 
465  if (*option == '+')
466  break;
467  i++;
468  if (i == (ssize_t) argc)
469  ThrowCompareException(OptionError,"MissingArgument",option);
470  compose=ParseCommandOption(MagickComposeOptions,MagickFalse,
471  argv[i]);
472  if (compose < 0)
473  ThrowCompareException(OptionError,"UnrecognizedComposeOperator",
474  argv[i]);
475  break;
476  }
477  if (LocaleCompare("compress",option+1) == 0)
478  {
479  ssize_t
480  compress;
481 
482  if (*option == '+')
483  break;
484  i++;
485  if (i == (ssize_t) argc)
486  ThrowCompareException(OptionError,"MissingArgument",option);
487  compress=ParseCommandOption(MagickCompressOptions,MagickFalse,
488  argv[i]);
489  if (compress < 0)
490  ThrowCompareException(OptionError,"UnrecognizedImageCompression",
491  argv[i]);
492  break;
493  }
494  if (LocaleCompare("concurrent",option+1) == 0)
495  break;
496  if (LocaleCompare("crop",option+1) == 0)
497  {
498  if (*option == '+')
499  break;
500  i++;
501  if (i == (ssize_t) argc)
502  ThrowCompareException(OptionError,"MissingArgument",option);
503  if (IsGeometry(argv[i]) == MagickFalse)
504  ThrowCompareInvalidArgumentException(option,argv[i]);
505  break;
506  }
507  ThrowCompareException(OptionError,"UnrecognizedOption",option)
508  }
509  case 'd':
510  {
511  if (LocaleCompare("debug",option+1) == 0)
512  {
513  LogEventType
514  event_mask;
515 
516  if (*option == '+')
517  break;
518  i++;
519  if (i == (ssize_t) argc)
520  ThrowCompareException(OptionError,"MissingArgument",option);
521  event_mask=SetLogEventMask(argv[i]);
522  if (event_mask == UndefinedEvents)
523  ThrowCompareException(OptionError,"UnrecognizedEventType",
524  argv[i]);
525  break;
526  }
527  if (LocaleCompare("decipher",option+1) == 0)
528  {
529  if (*option == '+')
530  break;
531  i++;
532  if (i == (ssize_t) argc)
533  ThrowCompareException(OptionError,"MissingArgument",option);
534  break;
535  }
536  if (LocaleCompare("define",option+1) == 0)
537  {
538  i++;
539  if (i == (ssize_t) argc)
540  ThrowCompareException(OptionError,"MissingArgument",option);
541  if (*option == '+')
542  {
543  const char
544  *define;
545 
546  define=GetImageOption(image_info,argv[i]);
547  if (define == (const char *) NULL)
548  ThrowCompareException(OptionError,"NoSuchOption",argv[i]);
549  break;
550  }
551  break;
552  }
553  if (LocaleCompare("delete",option+1) == 0)
554  {
555  if (*option == '+')
556  break;
557  i++;
558  if (i == (ssize_t) argc)
559  ThrowCompareException(OptionError,"MissingArgument",option);
560  if (IsSceneGeometry(argv[i],MagickFalse) == MagickFalse)
561  ThrowCompareInvalidArgumentException(option,argv[i]);
562  break;
563  }
564  if (LocaleCompare("density",option+1) == 0)
565  {
566  if (*option == '+')
567  break;
568  i++;
569  if (i == (ssize_t) argc)
570  ThrowCompareException(OptionError,"MissingArgument",option);
571  if (IsGeometry(argv[i]) == MagickFalse)
572  ThrowCompareInvalidArgumentException(option,argv[i]);
573  break;
574  }
575  if (LocaleCompare("depth",option+1) == 0)
576  {
577  if (*option == '+')
578  break;
579  i++;
580  if (i == (ssize_t) argc)
581  ThrowCompareException(OptionError,"MissingArgument",option);
582  if (IsGeometry(argv[i]) == MagickFalse)
583  ThrowCompareInvalidArgumentException(option,argv[i]);
584  break;
585  }
586  if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
587  {
588  if (*option == '+')
589  break;
590  i++;
591  if (i == (ssize_t) argc)
592  ThrowCompareException(OptionError,"MissingArgument",option);
593  if (IsGeometry(argv[i]) == MagickFalse)
594  ThrowCompareInvalidArgumentException(option,argv[i]);
595  if (*option == '+')
596  dissimilarity_threshold=DefaultDissimilarityThreshold;
597  else
598  dissimilarity_threshold=StringToDouble(argv[i],(char **) NULL);
599  break;
600  }
601  if (LocaleCompare("distort",option+1) == 0)
602  {
603  ssize_t
604  op;
605 
606  i++;
607  if (i == (ssize_t) argc)
608  ThrowCompareException(OptionError,"MissingArgument",option);
609  op=ParseCommandOption(MagickDistortOptions,MagickFalse,argv[i]);
610  if (op < 0)
611  ThrowCompareException(OptionError,"UnrecognizedDistortMethod",
612  argv[i]);
613  i++;
614  if (i == (ssize_t) argc)
615  ThrowCompareException(OptionError,"MissingArgument",option);
616  break;
617  }
618  if (LocaleCompare("duration",option+1) == 0)
619  {
620  if (*option == '+')
621  break;
622  i++;
623  if (i == (ssize_t) argc)
624  ThrowCompareException(OptionError,"MissingArgument",option);
625  if (IsGeometry(argv[i]) == MagickFalse)
626  ThrowCompareInvalidArgumentException(option,argv[i]);
627  break;
628  }
629  ThrowCompareException(OptionError,"UnrecognizedOption",option)
630  }
631  case 'e':
632  {
633  if (LocaleCompare("encipher",option+1) == 0)
634  {
635  if (*option == '+')
636  break;
637  i++;
638  if (i == (ssize_t) argc)
639  ThrowCompareException(OptionError,"MissingArgument",option);
640  break;
641  }
642  if (LocaleCompare("extract",option+1) == 0)
643  {
644  if (*option == '+')
645  break;
646  i++;
647  if (i == (ssize_t) argc)
648  ThrowCompareException(OptionError,"MissingArgument",option);
649  if (IsGeometry(argv[i]) == MagickFalse)
650  ThrowCompareInvalidArgumentException(option,argv[i]);
651  break;
652  }
653  ThrowCompareException(OptionError,"UnrecognizedOption",option)
654  }
655  case 'f':
656  {
657  if (LocaleCompare("format",option+1) == 0)
658  {
659  if (*option == '+')
660  break;
661  i++;
662  if (i == (ssize_t) argc)
663  ThrowCompareException(OptionError,"MissingArgument",option);
664  format=argv[i];
665  break;
666  }
667  if (LocaleCompare("fuzz",option+1) == 0)
668  {
669  if (*option == '+')
670  break;
671  i++;
672  if (i == (ssize_t) argc)
673  ThrowCompareException(OptionError,"MissingArgument",option);
674  if (IsGeometry(argv[i]) == MagickFalse)
675  ThrowCompareInvalidArgumentException(option,argv[i]);
676  break;
677  }
678  ThrowCompareException(OptionError,"UnrecognizedOption",option)
679  }
680  case 'g':
681  {
682  if (LocaleCompare("gravity",option+1) == 0)
683  {
684  ssize_t
685  gravity;
686 
687  if (*option == '+')
688  break;
689  i++;
690  if (i == (ssize_t) argc)
691  ThrowCompareException(OptionError,"MissingArgument",option);
692  gravity=ParseCommandOption(MagickGravityOptions,MagickFalse,
693  argv[i]);
694  if (gravity < 0)
695  ThrowCompareException(OptionError,"UnrecognizedGravityType",
696  argv[i]);
697  break;
698  }
699  ThrowCompareException(OptionError,"UnrecognizedOption",option)
700  }
701  case 'h':
702  {
703  if ((LocaleCompare("help",option+1) == 0) ||
704  (LocaleCompare("-help",option+1) == 0))
705  return(CompareUsage());
706  if (LocaleCompare("highlight-color",option+1) == 0)
707  {
708  if (*option == '+')
709  break;
710  i++;
711  if (i == (ssize_t) argc)
712  ThrowCompareException(OptionError,"MissingArgument",option);
713  break;
714  }
715  ThrowCompareException(OptionError,"UnrecognizedOption",option)
716  }
717  case 'i':
718  {
719  if (LocaleCompare("identify",option+1) == 0)
720  break;
721  if (LocaleCompare("interlace",option+1) == 0)
722  {
723  ssize_t
724  interlace;
725 
726  if (*option == '+')
727  break;
728  i++;
729  if (i == (ssize_t) argc)
730  ThrowCompareException(OptionError,"MissingArgument",option);
731  interlace=ParseCommandOption(MagickInterlaceOptions,MagickFalse,
732  argv[i]);
733  if (interlace < 0)
734  ThrowCompareException(OptionError,"UnrecognizedInterlaceType",
735  argv[i]);
736  break;
737  }
738  ThrowCompareException(OptionError,"UnrecognizedOption",option)
739  }
740  case 'l':
741  {
742  if (LocaleCompare("level",option+1) == 0)
743  {
744  i++;
745  if (i == (ssize_t) argc)
746  ThrowCompareException(OptionError,"MissingArgument",option);
747  if (IsGeometry(argv[i]) == MagickFalse)
748  ThrowCompareInvalidArgumentException(option,argv[i]);
749  break;
750  }
751  if (LocaleCompare("limit",option+1) == 0)
752  {
753  char
754  *p;
755 
756  double
757  value;
758 
759  ssize_t
760  resource;
761 
762  if (*option == '+')
763  break;
764  i++;
765  if (i == (ssize_t) argc)
766  ThrowCompareException(OptionError,"MissingArgument",option);
767  resource=ParseCommandOption(MagickResourceOptions,MagickFalse,
768  argv[i]);
769  if (resource < 0)
770  ThrowCompareException(OptionError,"UnrecognizedResourceType",
771  argv[i]);
772  i++;
773  if (i == (ssize_t) argc)
774  ThrowCompareException(OptionError,"MissingArgument",option);
775  value=StringToDouble(argv[i],&p);
776  (void) value;
777  if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0))
778  ThrowCompareInvalidArgumentException(option,argv[i]);
779  break;
780  }
781  if (LocaleCompare("list",option+1) == 0)
782  {
783  ssize_t
784  list;
785 
786  if (*option == '+')
787  break;
788  i++;
789  if (i == (ssize_t) argc)
790  ThrowCompareException(OptionError,"MissingArgument",option);
791  list=ParseCommandOption(MagickListOptions,MagickFalse,argv[i]);
792  if (list < 0)
793  ThrowCompareException(OptionError,"UnrecognizedListType",argv[i]);
794  status=MogrifyImageInfo(image_info,(int) (i-j+1),(const char **)
795  argv+j,exception);
796  DestroyCompare();
797  return(status == 0 ? MagickFalse : MagickTrue);
798  }
799  if (LocaleCompare("log",option+1) == 0)
800  {
801  if (*option == '+')
802  break;
803  i++;
804  if ((i == (ssize_t) argc) || (strchr(argv[i],'%') == (char *) NULL))
805  ThrowCompareException(OptionError,"MissingArgument",option);
806  break;
807  }
808  if (LocaleCompare("lowlight-color",option+1) == 0)
809  {
810  if (*option == '+')
811  break;
812  i++;
813  if (i == (ssize_t) argc)
814  ThrowCompareException(OptionError,"MissingArgument",option);
815  break;
816  }
817  ThrowCompareException(OptionError,"UnrecognizedOption",option)
818  }
819  case 'm':
820  {
821  if (LocaleCompare("matte",option+1) == 0)
822  break;
823  if (LocaleCompare("metric",option+1) == 0)
824  {
825  ssize_t
826  type;
827 
828  if (*option == '+')
829  break;
830  i++;
831  if (i == (ssize_t) argc)
832  ThrowCompareException(OptionError,"MissingArgument",option);
833  type=ParseCommandOption(MagickMetricOptions,MagickTrue,argv[i]);
834  if (type < 0)
835  ThrowCompareException(OptionError,"UnrecognizedMetricType",
836  argv[i]);
837  metric=(MetricType) type;
838  break;
839  }
840  if (LocaleCompare("monitor",option+1) == 0)
841  break;
842  ThrowCompareException(OptionError,"UnrecognizedOption",option)
843  }
844  case 'n':
845  {
846  if (LocaleCompare("negate",option+1) == 0)
847  break;
848  ThrowCompareException(OptionError,"UnrecognizedOption",option)
849  }
850  case 'p':
851  {
852  if (LocaleCompare("passphrase",option+1) == 0)
853  {
854  if (*option == '+')
855  break;
856  i++;
857  if (i == (ssize_t) argc)
858  ThrowCompareException(OptionError,"MissingArgument",option);
859  break;
860  }
861  if (LocaleCompare("precision",option+1) == 0)
862  {
863  if (*option == '+')
864  break;
865  i++;
866  if (i == (ssize_t) argc)
867  ThrowCompareException(OptionError,"MissingArgument",option);
868  if (IsGeometry(argv[i]) == MagickFalse)
869  ThrowCompareInvalidArgumentException(option,argv[i]);
870  break;
871  }
872  if (LocaleCompare("profile",option+1) == 0)
873  {
874  i++;
875  if (i == (ssize_t) argc)
876  ThrowCompareException(OptionError,"MissingArgument",option);
877  break;
878  }
879  ThrowCompareException(OptionError,"UnrecognizedOption",option)
880  }
881  case 'q':
882  {
883  if (LocaleCompare("quality",option+1) == 0)
884  {
885  if (*option == '+')
886  break;
887  i++;
888  if (i == (ssize_t) argc)
889  ThrowCompareException(OptionError,"MissingArgument",option);
890  if (IsGeometry(argv[i]) == MagickFalse)
891  ThrowCompareInvalidArgumentException(option,argv[i]);
892  break;
893  }
894  if (LocaleCompare("quantize",option+1) == 0)
895  {
896  ssize_t
897  colorspace;
898 
899  if (*option == '+')
900  break;
901  i++;
902  if (i == (ssize_t) argc)
903  ThrowCompareException(OptionError,"MissingArgument",option);
904  colorspace=ParseCommandOption(MagickColorspaceOptions,
905  MagickFalse,argv[i]);
906  if (colorspace < 0)
907  ThrowCompareException(OptionError,"UnrecognizedColorspace",
908  argv[i]);
909  break;
910  }
911  if (LocaleCompare("quiet",option+1) == 0)
912  break;
913  ThrowCompareException(OptionError,"UnrecognizedOption",option)
914  }
915  case 'r':
916  {
917  if (LocaleCompare("read-mask",option+1) == 0)
918  {
919  if (*option == '+')
920  break;
921  i++;
922  if (i == (ssize_t) argc)
923  ThrowCompareException(OptionError,"MissingArgument",option);
924  break;
925  }
926  if (LocaleCompare("regard-warnings",option+1) == 0)
927  break;
928  if (LocaleCompare("repage",option+1) == 0)
929  {
930  if (*option == '+')
931  break;
932  i++;
933  if (i == (ssize_t) argc)
934  ThrowCompareException(OptionError,"MissingArgument",option);
935  if (IsGeometry(argv[i]) == MagickFalse)
936  ThrowCompareInvalidArgumentException(option,argv[i]);
937  break;
938  }
939  if (LocaleCompare("resize",option+1) == 0)
940  {
941  if (*option == '+')
942  break;
943  i++;
944  if (i == (ssize_t) argc)
945  ThrowCompareException(OptionError,"MissingArgument",option);
946  if (IsGeometry(argv[i]) == MagickFalse)
947  ThrowCompareInvalidArgumentException(option,argv[i]);
948  break;
949  }
950  if (LocaleNCompare("respect-parentheses",option+1,17) == 0)
951  {
952  respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse;
953  break;
954  }
955  if (LocaleCompare("rotate",option+1) == 0)
956  {
957  i++;
958  if (i == (ssize_t) argc)
959  ThrowCompareException(OptionError,"MissingArgument",option);
960  if (IsGeometry(argv[i]) == MagickFalse)
961  ThrowCompareInvalidArgumentException(option,argv[i]);
962  break;
963  }
964  ThrowCompareException(OptionError,"UnrecognizedOption",option)
965  }
966  case 's':
967  {
968  if (LocaleCompare("sampling-factor",option+1) == 0)
969  {
970  if (*option == '+')
971  break;
972  i++;
973  if (i == (ssize_t) argc)
974  ThrowCompareException(OptionError,"MissingArgument",option);
975  if (IsGeometry(argv[i]) == MagickFalse)
976  ThrowCompareInvalidArgumentException(option,argv[i]);
977  break;
978  }
979  if (LocaleCompare("seed",option+1) == 0)
980  {
981  if (*option == '+')
982  break;
983  i++;
984  if (i == (ssize_t) argc)
985  ThrowCompareException(OptionError,"MissingArgument",option);
986  if (IsGeometry(argv[i]) == MagickFalse)
987  ThrowCompareInvalidArgumentException(option,argv[i]);
988  break;
989  }
990  if (LocaleCompare("separate",option+1) == 0)
991  break;
992  if (LocaleCompare("set",option+1) == 0)
993  {
994  i++;
995  if (i == (ssize_t) argc)
996  ThrowCompareException(OptionError,"MissingArgument",option);
997  if (*option == '+')
998  break;
999  i++;
1000  if (i == (ssize_t) argc)
1001  ThrowCompareException(OptionError,"MissingArgument",option);
1002  break;
1003  }
1004  if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
1005  {
1006  i++;
1007  if (i == (ssize_t) argc)
1008  ThrowCompareException(OptionError,"MissingArgument",option);
1009  if (IsGeometry(argv[i]) == MagickFalse)
1010  ThrowCompareInvalidArgumentException(option,argv[i]);
1011  break;
1012  }
1013  if (LocaleCompare("similarity-threshold",option+1) == 0)
1014  {
1015  if (*option == '+')
1016  break;
1017  i++;
1018  if (i == (ssize_t) argc)
1019  ThrowCompareException(OptionError,"MissingArgument",option);
1020  if (IsGeometry(argv[i]) == MagickFalse)
1021  ThrowCompareInvalidArgumentException(option,argv[i]);
1022  if (*option == '+')
1023  similarity_threshold=DefaultSimilarityThreshold;
1024  else
1025  similarity_threshold=StringToDouble(argv[i],(char **) NULL);
1026  break;
1027  }
1028  if (LocaleCompare("size",option+1) == 0)
1029  {
1030  if (*option == '+')
1031  break;
1032  i++;
1033  if (i == (ssize_t) argc)
1034  ThrowCompareException(OptionError,"MissingArgument",option);
1035  if (IsGeometry(argv[i]) == MagickFalse)
1036  ThrowCompareInvalidArgumentException(option,argv[i]);
1037  break;
1038  }
1039  if (LocaleCompare("subimage-search",option+1) == 0)
1040  {
1041  if (*option == '+')
1042  {
1043  subimage_search=MagickFalse;
1044  break;
1045  }
1046  subimage_search=MagickTrue;
1047  break;
1048  }
1049  if (LocaleCompare("synchronize",option+1) == 0)
1050  break;
1051  ThrowCompareException(OptionError,"UnrecognizedOption",option)
1052  }
1053  case 't':
1054  {
1055  if (LocaleCompare("taint",option+1) == 0)
1056  break;
1057  if (LocaleCompare("transparent-color",option+1) == 0)
1058  {
1059  if (*option == '+')
1060  break;
1061  i++;
1062  if (i == (ssize_t) argc)
1063  ThrowCompareException(OptionError,"MissingArgument",option);
1064  break;
1065  }
1066  if (LocaleCompare("trim",option+1) == 0)
1067  break;
1068  if (LocaleCompare("type",option+1) == 0)
1069  {
1070  ssize_t
1071  type;
1072 
1073  if (*option == '+')
1074  break;
1075  i++;
1076  if (i == (ssize_t) argc)
1077  ThrowCompareException(OptionError,"MissingArgument",option);
1078  type=ParseCommandOption(MagickTypeOptions,MagickFalse,argv[i]);
1079  if (type < 0)
1080  ThrowCompareException(OptionError,"UnrecognizedImageType",
1081  argv[i]);
1082  break;
1083  }
1084  ThrowCompareException(OptionError,"UnrecognizedOption",option)
1085  }
1086  case 'v':
1087  {
1088  if (LocaleCompare("verbose",option+1) == 0)
1089  break;
1090  if ((LocaleCompare("version",option+1) == 0) ||
1091  (LocaleCompare("-version",option+1) == 0))
1092  {
1093  ListMagickVersion(stdout);
1094  break;
1095  }
1096  if (LocaleCompare("virtual-pixel",option+1) == 0)
1097  {
1098  ssize_t
1099  method;
1100 
1101  if (*option == '+')
1102  break;
1103  i++;
1104  if (i == (ssize_t) argc)
1105  ThrowCompareException(OptionError,"MissingArgument",option);
1106  method=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1107  argv[i]);
1108  if (method < 0)
1109  ThrowCompareException(OptionError,
1110  "UnrecognizedVirtualPixelMethod",argv[i]);
1111  break;
1112  }
1113  ThrowCompareException(OptionError,"UnrecognizedOption",option)
1114  }
1115  case 'w':
1116  {
1117  if (LocaleCompare("write",option+1) == 0)
1118  {
1119  i++;
1120  if (i == (ssize_t) argc)
1121  ThrowCompareException(OptionError,"MissingArgument",option);
1122  break;
1123  }
1124  if (LocaleCompare("write-mask",option+1) == 0)
1125  {
1126  if (*option == '+')
1127  break;
1128  i++;
1129  if (i == (ssize_t) argc)
1130  ThrowCompareException(OptionError,"MissingArgument",option);
1131  break;
1132  }
1133  ThrowCompareException(OptionError,"UnrecognizedOption",option)
1134  }
1135  case '?':
1136  break;
1137  default:
1138  ThrowCompareException(OptionError,"UnrecognizedOption",option)
1139  }
1140  fire=(GetCommandOptionFlags(MagickCommandOptions,MagickFalse,option) &
1141  FireOptionFlag) == 0 ? MagickFalse : MagickTrue;
1142  if (fire != MagickFalse)
1143  FireImageStack(MagickTrue,MagickTrue,MagickTrue);
1144  }
1145  if (k != 0)
1146  ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]);
1147  if (i-- != (ssize_t) (argc-1))
1148  ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
1149  if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
1150  ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
1151  FinalizeImageSettings(image_info,image,MagickTrue);
1152  if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
1153  ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
1154  image=GetImageFromList(image,0);
1155  reconstruct_image=GetImageFromList(image,1);
1156  offset.x=0;
1157  offset.y=0;
1158  if (subimage_search != MagickFalse)
1159  {
1160  similarity_image=SimilarityImage(image,reconstruct_image,metric,
1161  similarity_threshold,&offset,&similarity_metric,exception);
1162  if (similarity_metric > dissimilarity_threshold)
1163  ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename);
1164  }
1165  if ((reconstruct_image->columns == image->columns) &&
1166  (reconstruct_image->rows == image->rows))
1167  difference_image=CompareImages(image,reconstruct_image,metric,&distortion,
1168  exception);
1169  else
1170  if (similarity_image == (Image *) NULL)
1171  difference_image=CompareImages(image,reconstruct_image,metric,&distortion,
1172  exception);
1173  else
1174  {
1175  Image
1176  *composite_image;
1177 
1178  /*
1179  Determine if reconstructed image is a subimage of the image.
1180  */
1181  composite_image=CloneImage(image,0,0,MagickTrue,exception);
1182  if (composite_image == (Image *) NULL)
1183  difference_image=CompareImages(image,reconstruct_image,metric,
1184  &distortion,exception);
1185  else
1186  {
1187  Image
1188  *distort_image;
1189 
1190  RectangleInfo
1191  page;
1192 
1193  (void) CompositeImage(composite_image,reconstruct_image,
1194  CopyCompositeOp,MagickTrue,offset.x,offset.y,exception);
1195  difference_image=CompareImages(image,composite_image,metric,
1196  &distortion,exception);
1197  if (difference_image != (Image *) NULL)
1198  {
1199  difference_image->page.x=offset.x;
1200  difference_image->page.y=offset.y;
1201  }
1202  composite_image=DestroyImage(composite_image);
1203  page.width=reconstruct_image->columns;
1204  page.height=reconstruct_image->rows;
1205  page.x=offset.x;
1206  page.y=offset.y;
1207  distort_image=CropImage(image,&page,exception);
1208  if (distort_image != (Image *) NULL)
1209  {
1210  Image
1211  *sans_image;
1212 
1213  sans_image=CompareImages(distort_image,reconstruct_image,metric,
1214  &distortion,exception);
1215  distort_image=DestroyImage(distort_image);
1216  if (sans_image != (Image *) NULL)
1217  sans_image=DestroyImage(sans_image);
1218  }
1219  }
1220  if (difference_image != (Image *) NULL)
1221  {
1222  AppendImageToList(&difference_image,similarity_image);
1223  similarity_image=(Image *) NULL;
1224  }
1225  }
1226  if (difference_image == (Image *) NULL)
1227  status=0;
1228  else
1229  {
1230  if (image_info->verbose != MagickFalse)
1231  (void) SetImageColorMetric(image,reconstruct_image,exception);
1232  if (*difference_image->magick == '\0')
1233  (void) CopyMagickString(difference_image->magick,image->magick,
1235  if (image_info->verbose == MagickFalse)
1236  {
1237  switch (metric)
1238  {
1239  case FuzzErrorMetric:
1240  case MeanAbsoluteErrorMetric:
1241  case MeanSquaredErrorMetric:
1242  case PeakAbsoluteErrorMetric:
1243  case RootMeanSquaredErrorMetric:
1244  {
1245  (void) FormatLocaleFile(stderr,"%.*g (%.*g)",GetMagickPrecision(),
1246  QuantumRange*distortion,GetMagickPrecision(),
1247  (double) distortion);
1248  break;
1249  }
1250  case AbsoluteErrorMetric:
1251  case NormalizedCrossCorrelationErrorMetric:
1252  case PeakSignalToNoiseRatioErrorMetric:
1253  case PerceptualHashErrorMetric:
1254  case StructuralSimilarityErrorMetric:
1255  case StructuralDissimilarityErrorMetric:
1256  {
1257  (void) FormatLocaleFile(stderr,"%.*g",GetMagickPrecision(),
1258  distortion);
1259  break;
1260  }
1261  case MeanErrorPerPixelErrorMetric:
1262  {
1263  (void) FormatLocaleFile(stderr,"%.*g (%.*g, %.*g)",
1264  GetMagickPrecision(),distortion,
1265  GetMagickPrecision(),image->error.normalized_mean_error,
1266  GetMagickPrecision(),image->error.normalized_maximum_error);
1267  break;
1268  }
1269  case UndefinedErrorMetric:
1270  break;
1271  }
1272  if (subimage_search != MagickFalse)
1273  (void) FormatLocaleFile(stderr," @ %.20g,%.20g",
1274  (double) difference_image->page.x,
1275  (double) difference_image->page.y);
1276  }
1277  else
1278  {
1279  double
1280  *channel_distortion;
1281 
1282  channel_distortion=GetImageDistortions(image,reconstruct_image,
1283  metric,exception);
1284  (void) FormatLocaleFile(stderr,"Image: %s\n",image->filename);
1285  if ((reconstruct_image->columns != image->columns) ||
1286  (reconstruct_image->rows != image->rows))
1287  (void) FormatLocaleFile(stderr,"Offset: %.20g,%.20g\n",(double)
1288  difference_image->page.x,(double) difference_image->page.y);
1289  (void) FormatLocaleFile(stderr," Channel distortion: %s\n",
1290  CommandOptionToMnemonic(MagickMetricOptions,(ssize_t) metric));
1291  switch (metric)
1292  {
1293  case FuzzErrorMetric:
1294  case MeanAbsoluteErrorMetric:
1295  case MeanSquaredErrorMetric:
1296  case PeakAbsoluteErrorMetric:
1297  case RootMeanSquaredErrorMetric:
1298  {
1299  switch (image->colorspace)
1300  {
1301  case RGBColorspace:
1302  default:
1303  {
1304  (void) FormatLocaleFile(stderr," red: %.*g (%.*g)\n",
1305  GetMagickPrecision(),QuantumRange*
1306  channel_distortion[RedPixelChannel],GetMagickPrecision(),
1307  channel_distortion[RedPixelChannel]);
1308  (void) FormatLocaleFile(stderr," green: %.*g (%.*g)\n",
1309  GetMagickPrecision(),QuantumRange*
1310  channel_distortion[GreenPixelChannel],GetMagickPrecision(),
1311  channel_distortion[GreenPixelChannel]);
1312  (void) FormatLocaleFile(stderr," blue: %.*g (%.*g)\n",
1313  GetMagickPrecision(),QuantumRange*
1314  channel_distortion[BluePixelChannel],GetMagickPrecision(),
1315  channel_distortion[BluePixelChannel]);
1316  if (image->alpha_trait != UndefinedPixelTrait)
1317  (void) FormatLocaleFile(stderr," alpha: %.*g (%.*g)\n",
1318  GetMagickPrecision(),QuantumRange*
1319  channel_distortion[AlphaPixelChannel],
1320  GetMagickPrecision(),
1321  channel_distortion[AlphaPixelChannel]);
1322  break;
1323  }
1324  case CMYKColorspace:
1325  {
1326  (void) FormatLocaleFile(stderr," cyan: %.*g (%.*g)\n",
1327  GetMagickPrecision(),QuantumRange*
1328  channel_distortion[CyanPixelChannel],GetMagickPrecision(),
1329  channel_distortion[CyanPixelChannel]);
1330  (void) FormatLocaleFile(stderr," magenta: %.*g (%.*g)\n",
1331  GetMagickPrecision(),QuantumRange*
1332  channel_distortion[MagentaPixelChannel],
1333  GetMagickPrecision(),
1334  channel_distortion[MagentaPixelChannel]);
1335  (void) FormatLocaleFile(stderr," yellow: %.*g (%.*g)\n",
1336  GetMagickPrecision(),QuantumRange*
1337  channel_distortion[YellowPixelChannel],GetMagickPrecision(),
1338  channel_distortion[YellowPixelChannel]);
1339  (void) FormatLocaleFile(stderr," black: %.*g (%.*g)\n",
1340  GetMagickPrecision(),QuantumRange*
1341  channel_distortion[BlackPixelChannel],GetMagickPrecision(),
1342  channel_distortion[BlackPixelChannel]);
1343  if (image->alpha_trait != UndefinedPixelTrait)
1344  (void) FormatLocaleFile(stderr," alpha: %.*g (%.*g)\n",
1345  GetMagickPrecision(),QuantumRange*
1346  channel_distortion[AlphaPixelChannel],
1347  GetMagickPrecision(),
1348  channel_distortion[AlphaPixelChannel]);
1349  break;
1350  }
1351  case LinearGRAYColorspace:
1352  case GRAYColorspace:
1353  {
1354  (void) FormatLocaleFile(stderr," gray: %.*g (%.*g)\n",
1355  GetMagickPrecision(),QuantumRange*
1356  channel_distortion[GrayPixelChannel],GetMagickPrecision(),
1357  channel_distortion[GrayPixelChannel]);
1358  if (image->alpha_trait != UndefinedPixelTrait)
1359  (void) FormatLocaleFile(stderr," alpha: %.*g (%.*g)\n",
1360  GetMagickPrecision(),QuantumRange*
1361  channel_distortion[AlphaPixelChannel],
1362  GetMagickPrecision(),
1363  channel_distortion[AlphaPixelChannel]);
1364  break;
1365  }
1366  }
1367  (void) FormatLocaleFile(stderr," all: %.*g (%.*g)\n",
1368  GetMagickPrecision(),QuantumRange*
1369  channel_distortion[MaxPixelChannels],GetMagickPrecision(),
1370  channel_distortion[MaxPixelChannels]);
1371  break;
1372  }
1373  case AbsoluteErrorMetric:
1374  case NormalizedCrossCorrelationErrorMetric:
1375  case PeakSignalToNoiseRatioErrorMetric:
1376  case PerceptualHashErrorMetric:
1377  case StructuralSimilarityErrorMetric:
1378  case StructuralDissimilarityErrorMetric:
1379  {
1380  switch (image->colorspace)
1381  {
1382  case RGBColorspace:
1383  default:
1384  {
1385  (void) FormatLocaleFile(stderr," red: %.*g\n",
1386  GetMagickPrecision(),channel_distortion[RedPixelChannel]);
1387  (void) FormatLocaleFile(stderr," green: %.*g\n",
1388  GetMagickPrecision(),channel_distortion[GreenPixelChannel]);
1389  (void) FormatLocaleFile(stderr," blue: %.*g\n",
1390  GetMagickPrecision(),channel_distortion[BluePixelChannel]);
1391  if (image->alpha_trait != UndefinedPixelTrait)
1392  (void) FormatLocaleFile(stderr," alpha: %.*g\n",
1393  GetMagickPrecision(),
1394  channel_distortion[AlphaPixelChannel]);
1395  break;
1396  }
1397  case CMYKColorspace:
1398  {
1399  (void) FormatLocaleFile(stderr," cyan: %.*g\n",
1400  GetMagickPrecision(),channel_distortion[CyanPixelChannel]);
1401  (void) FormatLocaleFile(stderr," magenta: %.*g\n",
1402  GetMagickPrecision(),
1403  channel_distortion[MagentaPixelChannel]);
1404  (void) FormatLocaleFile(stderr," yellow: %.*g\n",
1405  GetMagickPrecision(),
1406  channel_distortion[YellowPixelChannel]);
1407  (void) FormatLocaleFile(stderr," black: %.*g\n",
1408  GetMagickPrecision(),
1409  channel_distortion[BlackPixelChannel]);
1410  if (image->alpha_trait != UndefinedPixelTrait)
1411  (void) FormatLocaleFile(stderr," alpha: %.*g\n",
1412  GetMagickPrecision(),
1413  channel_distortion[AlphaPixelChannel]);
1414  break;
1415  }
1416  case LinearGRAYColorspace:
1417  case GRAYColorspace:
1418  {
1419  (void) FormatLocaleFile(stderr," gray: %.*g\n",
1420  GetMagickPrecision(),channel_distortion[GrayPixelChannel]);
1421  if (image->alpha_trait != UndefinedPixelTrait)
1422  (void) FormatLocaleFile(stderr," alpha: %.*g\n",
1423  GetMagickPrecision(),
1424  channel_distortion[AlphaPixelChannel]);
1425  break;
1426  }
1427  }
1428  (void) FormatLocaleFile(stderr," all: %.*g\n",
1429  GetMagickPrecision(),channel_distortion[MaxPixelChannels]);
1430  break;
1431  }
1432  case MeanErrorPerPixelErrorMetric:
1433  {
1434  (void) FormatLocaleFile(stderr," %.*g (%.*g, %.*g)\n",
1435  GetMagickPrecision(),channel_distortion[MaxPixelChannels],
1436  GetMagickPrecision(),image->error.normalized_mean_error,
1437  GetMagickPrecision(),image->error.normalized_maximum_error);
1438  break;
1439  }
1440  case UndefinedErrorMetric:
1441  break;
1442  }
1443  channel_distortion=(double *) RelinquishMagickMemory(
1444  channel_distortion);
1445  if (subimage_search != MagickFalse)
1446  (void) FormatLocaleFile(stderr," Offset: %.20g,%.20g\n",(double)
1447  difference_image->page.x,(double) difference_image->page.y);
1448  }
1449  status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
1450  if ((metadata != (char **) NULL) && (format != (char *) NULL))
1451  {
1452  char
1453  *text;
1454 
1455  text=InterpretImageProperties(image_info,difference_image,format,
1456  exception);
1457  if (text == (char *) NULL)
1458  ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
1459  GetExceptionMessage(errno));
1460  (void) ConcatenateString(&(*metadata),text);
1461  text=DestroyString(text);
1462  }
1463  difference_image=DestroyImageList(difference_image);
1464  }
1465  DestroyCompare();
1466  if ((metric == NormalizedCrossCorrelationErrorMetric) ||
1467  (metric == UndefinedErrorMetric))
1468  {
1469  if (fabs(distortion-1.0) > CompareEpsilon)
1470  (void) SetImageOption(image_info,"compare:dissimilar","true");
1471  }
1472  else
1473  if (fabs(distortion) > CompareEpsilon)
1474  (void) SetImageOption(image_info,"compare:dissimilar","true");
1475  return(status != 0 ? MagickTrue : MagickFalse);
1476 }
#define FinalizeImageSettings(image_info, image, advance)
#define ThrowCompareException(asperity, tag, option)
#define NewImageStack()
#define WandExport
#define AppendImageStack(images)
#define CompareEpsilon
#define DestroyCompare()
WandExport MagickBooleanType MogrifyImageInfo(ImageInfo *image_info, const int argc, const char **argv, ExceptionInfo *exception)
Definition: mogrify.c:6578
#define MagickPathExtent
#define ReadCommandlLine(argc, argv)
Definition: studio.h:254
WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info, int argc, char **argv, char **metadata, ExceptionInfo *exception)
Definition: compare.c:198
#define DefaultDissimilarityThreshold
#define PopImageStack()
#define ThrowCompareInvalidArgumentException(option, argument)
static MagickBooleanType CompareUsage(void)
Definition: compare.c:83
#define DefaultSimilarityThreshold
#define PushImageStack()
#define FireImageStack(postfix, advance, fire)
#define MaxImageStackDepth