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