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