44#include "MagickWand/studio.h"
45#include "MagickWand/MagickWand.h"
46#include "MagickWand/mogrify-private.h"
47#include "MagickCore/image-private.h"
48#include "MagickCore/string-private.h"
84static MagickBooleanType CompareUsage(
void)
88 " -separate separate an image channel into a grayscale image",
90 " -channel mask set the image channel mask\n"
91 " -debug events display copious debugging information\n"
92 " -help print program options\n"
93 " -list type print a list of supported option arguments\n"
94 " -log format format of debugging information",
96 " -auto-orient automagically orient (rotate) image\n"
97 " -brightness-contrast geometry\n"
98 " improve brightness / contrast of the image\n"
99 " -distort method args\n"
100 " distort images according to given method and args\n"
101 " -level value adjust the level of image contrast\n"
102 " -resize geometry resize the image\n"
103 " -rotate degrees apply Paeth rotation to the image\n"
104 " -sigmoidal-contrast geometry\n"
105 " increase the contrast without saturating highlights or\n"
106 " -trim trim image edges\n"
107 " -write filename write images to this file",
108 sequence_operators[] =
109 " -crop geometry cut out a rectangular region of the image",
111 " -alpha option on, activate, off, deactivate, set, opaque, copy\n"
112 " transparent, extract, background, or shape\n"
113 " -authenticate password\n"
114 " decipher image with this password\n"
115 " -background color background color\n"
116 " -colorspace type alternate image colorspace\n"
117 " -compose operator set image composite operator\n"
118 " -compress type type of pixel compression when writing the image\n"
119 " -decipher filename convert cipher pixels to plain pixels\n"
120 " -define format:option\n"
121 " define one or more image format options\n"
122 " -density geometry horizontal and vertical density of the image\n"
123 " -depth value image depth\n"
124 " -dissimilarity-threshold value\n"
125 " maximum distortion for (sub)image match\n"
126 " -encipher filename convert plain pixels to cipher pixels\n"
127 " -extract geometry extract area from image\n"
128 " -format \"string\" output formatted image characteristics\n"
129 " -fuzz distance colors within this distance are considered equal\n"
130 " -gravity type horizontal and vertical text placement\n"
131 " -highlight-color color\n"
132 " emphasize pixel differences with this color\n"
133 " -identify identify the format and characteristics of the image\n"
134 " -interlace type type of image interlacing scheme\n"
135 " -limit type value pixel cache resource limit\n"
136 " -lowlight-color color\n"
137 " de-emphasize pixel differences with this color\n"
138 " -metric type measure differences between images with this metric\n"
139 " -monitor monitor progress\n"
140 " -negate replace every pixel with its complementary color \n"
141 " -passphrase filename get the passphrase from this file\n"
142 " -precision value maximum number of significant digits to print\n"
143 " -profile filename add, delete, or apply an image profile\n"
144 " -quality value JPEG/MIFF/PNG compression level\n"
145 " -quiet suppress all warning messages\n"
146 " -quantize colorspace reduce colors in this colorspace\n"
147 " -read-mask filename associate a read mask with the image\n"
148 " -regard-warnings pay attention to warning messages\n"
149 " -respect-parentheses settings remain in effect until parenthesis boundary\n"
150 " -sampling-factor geometry\n"
151 " horizontal and vertical sampling factor\n"
152 " -seed value seed a new sequence of pseudo-random numbers\n"
153 " -set attribute value set an image attribute\n"
154 " -quality value JPEG/MIFF/PNG compression level\n"
155 " -repage geometry size and location of an image canvas\n"
156 " -similarity-threshold value\n"
157 " minimum distortion for (sub)image match\n"
158 " -size geometry width and height of image\n"
159 " -subimage-search search for subimage\n"
160 " -synchronize synchronize image to storage device\n"
161 " -taint declare the image as modified\n"
162 " -transparent-color color\n"
163 " transparent color\n"
164 " -type type image type\n"
165 " -verbose print detailed information about the image\n"
166 " -version print version information\n"
167 " -virtual-pixel method\n"
168 " virtual pixel access method\n"
169 " -write-mask filename associate a write mask with the image",
171 " -delete indexes delete the image from the image sequence";
173 ListMagickVersion(stdout);
174 (void) printf(
"Usage: %s [options ...] image reconstruct difference\n",
176 (void) printf(
"\nImage Settings:\n");
177 (void) puts(settings);
178 (void) printf(
"\nImage Operators:\n");
179 (void) puts(operators);
180 (void) printf(
"\nImage Channel Operators:\n");
181 (void) puts(channel_operators);
182 (void) printf(
"\nImage Sequence Operators:\n");
183 (void) puts(sequence_operators);
184 (void) printf(
"\nImage Stack Operators:\n");
185 (void) puts(stack_operators);
186 (void) printf(
"\nMiscellaneous Options:\n");
187 (void) puts(miscellaneous);
189 "\nBy default, the image format of 'file' is determined by its magic\n");
191 "number. To specify a particular image format, precede the filename\n");
193 "with an image format name and a colon (i.e. ps:image) or specify the\n");
195 "image type as the filename suffix (i.e. image.ps). Specify 'file' as\n");
196 (void) printf(
"'-' for standard input or output.\n");
200WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info,
201 int argc,
char **argv,
char **metadata,ExceptionInfo *exception)
203#define CompareEpsilon (1.0e-06)
204#define DefaultDissimilarityThreshold (1.0/MagickPI)
205#define DefaultSimilarityThreshold (-1.0)
206#define DestroyCompare() \
208 if (similarity_image != (Image *) NULL) \
209 similarity_image=DestroyImageList(similarity_image); \
210 if (difference_image != (Image *) NULL) \
211 difference_image=DestroyImageList(difference_image); \
212 DestroyImageStack(); \
213 for (i=0; i < (ssize_t) argc; i++) \
214 argv[i]=DestroyString(argv[i]); \
215 argv=(char **) RelinquishMagickMemory(argv); \
217#define ThrowCompareException(asperity,tag,option) \
219 if (exception->severity < (asperity)) \
220 (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
223 return(MagickFalse); \
225#define ThrowCompareInvalidArgumentException(option,argument) \
227 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
228 "InvalidArgument","'%s': %s",option,argument); \
230 return(MagickFalse); \
241 dissimilarity_threshold,
244 similarity_threshold;
248 *image = (Image *) NULL,
253 image_stack[MaxImageStackDepth+1];
259 similar = MagickTrue,
281 assert(image_info != (ImageInfo *) NULL);
282 assert(image_info->signature == MagickCoreSignature);
283 assert(exception != (ExceptionInfo *) NULL);
284 if (IsEventLogging() != MagickFalse)
285 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
289 if ((LocaleCompare(
"version",option+1) == 0) ||
290 (LocaleCompare(
"-version",option+1) == 0))
292 ListMagickVersion(stdout);
298 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
299 "MissingArgument",
"%s",
"");
300 (void) CompareUsage();
303 difference_image=NewImageList();
304 similarity_image=NewImageList();
305 dissimilarity_threshold=DefaultDissimilarityThreshold;
306 similarity_threshold=DefaultSimilarityThreshold;
308 similarity_metric=0.0;
309 format=(
char *) NULL;
312 metric=UndefinedErrorMetric;
314 option=(
char *) NULL;
316 reconstruct_image=NewImageList();
317 respect_parentheses=MagickFalse;
319 subimage_search=MagickFalse;
323 ReadCommandlLine(argc,&argv);
324 status=ExpandFilenames(&argc,&argv);
325 if (status == MagickFalse)
326 ThrowCompareException(ResourceLimitError,
"MemoryAllocationFailed",
327 GetExceptionMessage(errno));
328 for (i=1; i < (ssize_t) (argc-1); i++)
331 if (LocaleCompare(option,
"(") == 0)
333 FireImageStack(MagickTrue,MagickTrue,pend);
334 if (k == MaxImageStackDepth)
335 ThrowCompareException(OptionError,
"ParenthesisNestedTooDeeply",
340 if (LocaleCompare(option,
")") == 0)
342 FireImageStack(MagickTrue,MagickTrue,MagickTrue);
344 ThrowCompareException(OptionError,
"UnableToParseExpression",option);
348 if (IsCommandOption(option) == MagickFalse)
356 FireImageStack(MagickFalse,MagickFalse,pend);
358 if ((LocaleCompare(filename,
"--") == 0) && (i < (ssize_t) (argc-1)))
360 images=ReadImages(image_info,filename,exception);
361 status&=(MagickStatusType) (images != (Image *) NULL) &&
362 (exception->severity < ErrorException);
363 if (images == (Image *) NULL)
365 AppendImageStack(images);
368 pend=image != (Image *) NULL ? MagickTrue : MagickFalse;
373 if (LocaleCompare(
"alpha",option+1) == 0)
381 if (i == (ssize_t) argc)
382 ThrowCompareException(OptionError,
"MissingArgument",option);
383 type=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,
386 ThrowCompareException(OptionError,
387 "UnrecognizedAlphaChannelOption",argv[i]);
390 if (LocaleCompare(
"auto-orient",option+1) == 0)
392 if (LocaleCompare(
"authenticate",option+1) == 0)
397 if (i == (ssize_t) argc)
398 ThrowCompareException(OptionError,
"MissingArgument",option);
401 ThrowCompareException(OptionError,
"UnrecognizedOption",option);
405 if (LocaleCompare(
"background",option+1) == 0)
410 if (i == (ssize_t) argc)
411 ThrowCompareException(OptionError,
"MissingArgument",option);
414 if (LocaleCompare(
"brightness-contrast",option+1) == 0)
417 if (i == (ssize_t) argc)
418 ThrowCompareException(OptionError,
"MissingArgument",option);
419 if (IsGeometry(argv[i]) == MagickFalse)
420 ThrowCompareInvalidArgumentException(option,argv[i]);
423 ThrowCompareException(OptionError,
"UnrecognizedOption",option);
427 if (LocaleCompare(
"cache",option+1) == 0)
432 if (i == (ssize_t) argc)
433 ThrowCompareException(OptionError,
"MissingArgument",option);
434 if (IsGeometry(argv[i]) == MagickFalse)
435 ThrowCompareInvalidArgumentException(option,argv[i]);
438 if (LocaleCompare(
"channel",option+1) == 0)
446 if (i == (ssize_t) argc)
447 ThrowCompareException(OptionError,
"MissingArgument",option);
448 channel=ParseChannelOption(argv[i]);
450 ThrowCompareException(OptionError,
"UnrecognizedChannelType",
454 if (LocaleCompare(
"colorspace",option+1) == 0)
462 if (i == (ssize_t) argc)
463 ThrowCompareException(OptionError,
"MissingArgument",option);
464 colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,
467 ThrowCompareException(OptionError,
"UnrecognizedColorspace",
471 if (LocaleCompare(
"compose",option+1) == 0)
479 if (i == (ssize_t) argc)
480 ThrowCompareException(OptionError,
"MissingArgument",option);
481 compose=ParseCommandOption(MagickComposeOptions,MagickFalse,
484 ThrowCompareException(OptionError,
"UnrecognizedComposeOperator",
488 if (LocaleCompare(
"compress",option+1) == 0)
496 if (i == (ssize_t) argc)
497 ThrowCompareException(OptionError,
"MissingArgument",option);
498 compress=ParseCommandOption(MagickCompressOptions,MagickFalse,
501 ThrowCompareException(OptionError,
"UnrecognizedImageCompression",
505 if (LocaleCompare(
"concurrent",option+1) == 0)
507 if (LocaleCompare(
"crop",option+1) == 0)
512 if (i == (ssize_t) argc)
513 ThrowCompareException(OptionError,
"MissingArgument",option);
514 if (IsGeometry(argv[i]) == MagickFalse)
515 ThrowCompareInvalidArgumentException(option,argv[i]);
518 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
522 if (LocaleCompare(
"debug",option+1) == 0)
530 if (i == (ssize_t) argc)
531 ThrowCompareException(OptionError,
"MissingArgument",option);
532 event_mask=SetLogEventMask(argv[i]);
533 if (event_mask == UndefinedEvents)
534 ThrowCompareException(OptionError,
"UnrecognizedEventType",
538 if (LocaleCompare(
"decipher",option+1) == 0)
543 if (i == (ssize_t) argc)
544 ThrowCompareException(OptionError,
"MissingArgument",option);
547 if (LocaleCompare(
"define",option+1) == 0)
550 if (i == (ssize_t) argc)
551 ThrowCompareException(OptionError,
"MissingArgument",option);
557 define=GetImageOption(image_info,argv[i]);
558 if (define == (
const char *) NULL)
559 ThrowCompareException(OptionError,
"NoSuchOption",argv[i]);
564 if (LocaleCompare(
"delete",option+1) == 0)
569 if (i == (ssize_t) argc)
570 ThrowCompareException(OptionError,
"MissingArgument",option);
571 if (IsSceneGeometry(argv[i],MagickFalse) == MagickFalse)
572 ThrowCompareInvalidArgumentException(option,argv[i]);
575 if (LocaleCompare(
"density",option+1) == 0)
580 if (i == (ssize_t) argc)
581 ThrowCompareException(OptionError,
"MissingArgument",option);
582 if (IsGeometry(argv[i]) == MagickFalse)
583 ThrowCompareInvalidArgumentException(option,argv[i]);
586 if (LocaleCompare(
"depth",option+1) == 0)
591 if (i == (ssize_t) argc)
592 ThrowCompareException(OptionError,
"MissingArgument",option);
593 if (IsGeometry(argv[i]) == MagickFalse)
594 ThrowCompareInvalidArgumentException(option,argv[i]);
597 if (LocaleCompare(
"dissimilarity-threshold",option+1) == 0)
602 if (i == (ssize_t) argc)
603 ThrowCompareException(OptionError,
"MissingArgument",option);
604 if (IsGeometry(argv[i]) == MagickFalse)
605 ThrowCompareInvalidArgumentException(option,argv[i]);
607 dissimilarity_threshold=DefaultDissimilarityThreshold;
609 dissimilarity_threshold=StringToDouble(argv[i],(
char **) NULL);
612 if (LocaleCompare(
"distort",option+1) == 0)
618 if (i == (ssize_t) argc)
619 ThrowCompareException(OptionError,
"MissingArgument",option);
620 op=ParseCommandOption(MagickDistortOptions,MagickFalse,argv[i]);
622 ThrowCompareException(OptionError,
"UnrecognizedDistortMethod",
625 if (i == (ssize_t) argc)
626 ThrowCompareException(OptionError,
"MissingArgument",option);
629 if (LocaleCompare(
"duration",option+1) == 0)
634 if (i == (ssize_t) argc)
635 ThrowCompareException(OptionError,
"MissingArgument",option);
636 if (IsGeometry(argv[i]) == MagickFalse)
637 ThrowCompareInvalidArgumentException(option,argv[i]);
640 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
644 if (LocaleCompare(
"encipher",option+1) == 0)
649 if (i == (ssize_t) argc)
650 ThrowCompareException(OptionError,
"MissingArgument",option);
653 if (LocaleCompare(
"extract",option+1) == 0)
658 if (i == (ssize_t) argc)
659 ThrowCompareException(OptionError,
"MissingArgument",option);
660 if (IsGeometry(argv[i]) == MagickFalse)
661 ThrowCompareInvalidArgumentException(option,argv[i]);
664 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
668 if (LocaleCompare(
"format",option+1) == 0)
673 if (i == (ssize_t) argc)
674 ThrowCompareException(OptionError,
"MissingArgument",option);
678 if (LocaleCompare(
"fuzz",option+1) == 0)
683 if (i == (ssize_t) argc)
684 ThrowCompareException(OptionError,
"MissingArgument",option);
685 if (IsGeometry(argv[i]) == MagickFalse)
686 ThrowCompareInvalidArgumentException(option,argv[i]);
689 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
693 if (LocaleCompare(
"gravity",option+1) == 0)
701 if (i == (ssize_t) argc)
702 ThrowCompareException(OptionError,
"MissingArgument",option);
703 gravity=ParseCommandOption(MagickGravityOptions,MagickFalse,
706 ThrowCompareException(OptionError,
"UnrecognizedGravityType",
710 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
714 if ((LocaleCompare(
"help",option+1) == 0) ||
715 (LocaleCompare(
"-help",option+1) == 0))
718 return(CompareUsage());
720 if (LocaleCompare(
"highlight-color",option+1) == 0)
725 if (i == (ssize_t) argc)
726 ThrowCompareException(OptionError,
"MissingArgument",option);
729 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
733 if (LocaleCompare(
"identify",option+1) == 0)
735 if (LocaleCompare(
"interlace",option+1) == 0)
743 if (i == (ssize_t) argc)
744 ThrowCompareException(OptionError,
"MissingArgument",option);
745 interlace=ParseCommandOption(MagickInterlaceOptions,MagickFalse,
748 ThrowCompareException(OptionError,
"UnrecognizedInterlaceType",
752 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
756 if (LocaleCompare(
"level",option+1) == 0)
759 if (i == (ssize_t) argc)
760 ThrowCompareException(OptionError,
"MissingArgument",option);
761 if (IsGeometry(argv[i]) == MagickFalse)
762 ThrowCompareInvalidArgumentException(option,argv[i]);
765 if (LocaleCompare(
"limit",option+1) == 0)
779 if (i == (ssize_t) argc)
780 ThrowCompareException(OptionError,
"MissingArgument",option);
781 resource=ParseCommandOption(MagickResourceOptions,MagickFalse,
784 ThrowCompareException(OptionError,
"UnrecognizedResourceType",
787 if (i == (ssize_t) argc)
788 ThrowCompareException(OptionError,
"MissingArgument",option);
789 value=StringToDouble(argv[i],&p);
791 if ((p == argv[i]) && (LocaleCompare(
"unlimited",argv[i]) != 0))
792 ThrowCompareInvalidArgumentException(option,argv[i]);
795 if (LocaleCompare(
"list",option+1) == 0)
803 if (i == (ssize_t) argc)
804 ThrowCompareException(OptionError,
"MissingArgument",option);
805 list=ParseCommandOption(MagickListOptions,MagickFalse,argv[i]);
807 ThrowCompareException(OptionError,
"UnrecognizedListType",argv[i]);
808 status=MogrifyImageInfo(image_info,(
int) (i-j+1),(
const char **)
811 return(status == 0 ? MagickFalse : MagickTrue);
813 if (LocaleCompare(
"log",option+1) == 0)
818 if ((i == (ssize_t) argc) || (strchr(argv[i],
'%') == (
char *) NULL))
819 ThrowCompareException(OptionError,
"MissingArgument",option);
822 if (LocaleCompare(
"lowlight-color",option+1) == 0)
827 if (i == (ssize_t) argc)
828 ThrowCompareException(OptionError,
"MissingArgument",option);
831 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
835 if (LocaleCompare(
"matte",option+1) == 0)
837 if (LocaleCompare(
"metric",option+1) == 0)
845 if (i == (ssize_t) argc)
846 ThrowCompareException(OptionError,
"MissingArgument",option);
847 type=ParseCommandOption(MagickMetricOptions,MagickTrue,argv[i]);
849 ThrowCompareException(OptionError,
"UnrecognizedMetricType",
851 metric=(MetricType) type;
854 if (LocaleCompare(
"monitor",option+1) == 0)
856 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
860 if (LocaleCompare(
"negate",option+1) == 0)
862 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
866 if (LocaleCompare(
"passphrase",option+1) == 0)
871 if (i == (ssize_t) argc)
872 ThrowCompareException(OptionError,
"MissingArgument",option);
875 if (LocaleCompare(
"precision",option+1) == 0)
880 if (i == (ssize_t) argc)
881 ThrowCompareException(OptionError,
"MissingArgument",option);
882 if (IsGeometry(argv[i]) == MagickFalse)
883 ThrowCompareInvalidArgumentException(option,argv[i]);
886 if (LocaleCompare(
"profile",option+1) == 0)
889 if (i == (ssize_t) argc)
890 ThrowCompareException(OptionError,
"MissingArgument",option);
893 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
897 if (LocaleCompare(
"quality",option+1) == 0)
902 if (i == (ssize_t) argc)
903 ThrowCompareException(OptionError,
"MissingArgument",option);
904 if (IsGeometry(argv[i]) == MagickFalse)
905 ThrowCompareInvalidArgumentException(option,argv[i]);
908 if (LocaleCompare(
"quantize",option+1) == 0)
916 if (i == (ssize_t) argc)
917 ThrowCompareException(OptionError,
"MissingArgument",option);
918 colorspace=ParseCommandOption(MagickColorspaceOptions,
919 MagickFalse,argv[i]);
921 ThrowCompareException(OptionError,
"UnrecognizedColorspace",
925 if (LocaleCompare(
"quiet",option+1) == 0)
927 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
931 if (LocaleCompare(
"read-mask",option+1) == 0)
936 if (i == (ssize_t) argc)
937 ThrowCompareException(OptionError,
"MissingArgument",option);
940 if (LocaleCompare(
"regard-warnings",option+1) == 0)
942 if (LocaleCompare(
"repage",option+1) == 0)
947 if (i == (ssize_t) argc)
948 ThrowCompareException(OptionError,
"MissingArgument",option);
949 if (IsGeometry(argv[i]) == MagickFalse)
950 ThrowCompareInvalidArgumentException(option,argv[i]);
953 if (LocaleCompare(
"resize",option+1) == 0)
958 if (i == (ssize_t) argc)
959 ThrowCompareException(OptionError,
"MissingArgument",option);
960 if (IsGeometry(argv[i]) == MagickFalse)
961 ThrowCompareInvalidArgumentException(option,argv[i]);
964 if (LocaleNCompare(
"respect-parentheses",option+1,17) == 0)
966 respect_parentheses=(*option ==
'-') ? MagickTrue : MagickFalse;
969 if (LocaleCompare(
"rotate",option+1) == 0)
972 if (i == (ssize_t) argc)
973 ThrowCompareException(OptionError,
"MissingArgument",option);
974 if (IsGeometry(argv[i]) == MagickFalse)
975 ThrowCompareInvalidArgumentException(option,argv[i]);
978 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
982 if (LocaleCompare(
"sampling-factor",option+1) == 0)
987 if (i == (ssize_t) argc)
988 ThrowCompareException(OptionError,
"MissingArgument",option);
989 if (IsGeometry(argv[i]) == MagickFalse)
990 ThrowCompareInvalidArgumentException(option,argv[i]);
993 if (LocaleCompare(
"seed",option+1) == 0)
998 if (i == (ssize_t) argc)
999 ThrowCompareException(OptionError,
"MissingArgument",option);
1000 if (IsGeometry(argv[i]) == MagickFalse)
1001 ThrowCompareInvalidArgumentException(option,argv[i]);
1004 if (LocaleCompare(
"separate",option+1) == 0)
1006 if (LocaleCompare(
"set",option+1) == 0)
1009 if (i == (ssize_t) argc)
1010 ThrowCompareException(OptionError,
"MissingArgument",option);
1014 if (i == (ssize_t) argc)
1015 ThrowCompareException(OptionError,
"MissingArgument",option);
1018 if (LocaleCompare(
"sigmoidal-contrast",option+1) == 0)
1021 if (i == (ssize_t) argc)
1022 ThrowCompareException(OptionError,
"MissingArgument",option);
1023 if (IsGeometry(argv[i]) == MagickFalse)
1024 ThrowCompareInvalidArgumentException(option,argv[i]);
1027 if (LocaleCompare(
"similarity-threshold",option+1) == 0)
1032 if (i == (ssize_t) argc)
1033 ThrowCompareException(OptionError,
"MissingArgument",option);
1034 if (IsGeometry(argv[i]) == MagickFalse)
1035 ThrowCompareInvalidArgumentException(option,argv[i]);
1037 similarity_threshold=DefaultSimilarityThreshold;
1039 similarity_threshold=StringToDouble(argv[i],(
char **) NULL);
1042 if (LocaleCompare(
"size",option+1) == 0)
1047 if (i == (ssize_t) argc)
1048 ThrowCompareException(OptionError,
"MissingArgument",option);
1049 if (IsGeometry(argv[i]) == MagickFalse)
1050 ThrowCompareInvalidArgumentException(option,argv[i]);
1053 if (LocaleCompare(
"subimage-search",option+1) == 0)
1057 subimage_search=MagickFalse;
1060 subimage_search=MagickTrue;
1063 if (LocaleCompare(
"synchronize",option+1) == 0)
1065 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
1069 if (LocaleCompare(
"taint",option+1) == 0)
1071 if (LocaleCompare(
"transparent-color",option+1) == 0)
1076 if (i == (ssize_t) argc)
1077 ThrowCompareException(OptionError,
"MissingArgument",option);
1080 if (LocaleCompare(
"trim",option+1) == 0)
1082 if (LocaleCompare(
"type",option+1) == 0)
1090 if (i == (ssize_t) argc)
1091 ThrowCompareException(OptionError,
"MissingArgument",option);
1092 type=ParseCommandOption(MagickTypeOptions,MagickFalse,argv[i]);
1094 ThrowCompareException(OptionError,
"UnrecognizedImageType",
1098 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
1102 if (LocaleCompare(
"verbose",option+1) == 0)
1104 if ((LocaleCompare(
"version",option+1) == 0) ||
1105 (LocaleCompare(
"-version",option+1) == 0))
1107 ListMagickVersion(stdout);
1110 if (LocaleCompare(
"virtual-pixel",option+1) == 0)
1118 if (i == (ssize_t) argc)
1119 ThrowCompareException(OptionError,
"MissingArgument",option);
1120 method=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1123 ThrowCompareException(OptionError,
1124 "UnrecognizedVirtualPixelMethod",argv[i]);
1127 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
1131 if (LocaleCompare(
"write",option+1) == 0)
1134 if (i == (ssize_t) argc)
1135 ThrowCompareException(OptionError,
"MissingArgument",option);
1138 if (LocaleCompare(
"write-mask",option+1) == 0)
1143 if (i == (ssize_t) argc)
1144 ThrowCompareException(OptionError,
"MissingArgument",option);
1147 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
1152 ThrowCompareException(OptionError,
"UnrecognizedOption",option)
1154 fire=(GetCommandOptionFlags(MagickCommandOptions,MagickFalse,option) &
1155 FireOptionFlag) == 0 ? MagickFalse : MagickTrue;
1156 if (fire != MagickFalse)
1157 FireImageStack(MagickTrue,MagickTrue,MagickTrue);
1160 ThrowCompareException(OptionError,
"UnbalancedParenthesis",argv[i]);
1161 if (i-- != (ssize_t) (argc-1))
1162 ThrowCompareException(OptionError,
"MissingAnImageFilename",argv[i]);
1163 if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
1164 ThrowCompareException(OptionError,
"MissingAnImageFilename",argv[i]);
1165 FinalizeImageSettings(image_info,image,MagickTrue);
1166 if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
1167 ThrowCompareException(OptionError,
"MissingAnImageFilename",argv[i]);
1168 image=GetImageFromList(image,0);
1169 reconstruct_image=GetImageFromList(image,1);
1172 if (subimage_search != MagickFalse)
1174 similarity_image=SimilarityImage(image,reconstruct_image,metric,
1175 similarity_threshold,&offset,&similarity_metric,exception);
1176 if (dissimilarity_threshold == DefaultDissimilarityThreshold)
1179 case PhaseCorrelationErrorMetric:
1180 case PeakSignalToNoiseRatioErrorMetric:
1182 dissimilarity_threshold=1.0;
1188 if (similarity_metric > (dissimilarity_threshold+MagickEpsilon))
1189 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
1190 "ImagesTooDissimilar",
"`%s'",image->filename);
1192 if (similarity_image == (Image *) NULL)
1193 difference_image=CompareImages(image,reconstruct_image,metric,&distortion,
1203 composite_image=CloneImage(image,0,0,MagickTrue,exception);
1204 if (composite_image == (Image *) NULL)
1205 difference_image=CompareImages(image,reconstruct_image,metric,
1206 &distortion,exception);
1215 (void) CompositeImage(composite_image,reconstruct_image,
1216 CopyCompositeOp,MagickTrue,offset.x,offset.y,exception);
1217 difference_image=CompareImages(image,composite_image,metric,
1218 &distortion,exception);
1219 if (difference_image != (Image *) NULL)
1221 difference_image->page.x=offset.x;
1222 difference_image->page.y=offset.y;
1224 composite_image=DestroyImage(composite_image);
1225 page.width=reconstruct_image->columns;
1226 page.height=reconstruct_image->rows;
1229 distort_image=CropImage(image,&page,exception);
1230 if (distort_image != (Image *) NULL)
1235 sans_image=CompareImages(distort_image,reconstruct_image,metric,
1236 &distortion,exception);
1237 distort_image=DestroyImage(distort_image);
1238 if (sans_image != (Image *) NULL)
1239 sans_image=DestroyImage(sans_image);
1242 if (difference_image != (Image *) NULL)
1244 AppendImageToList(&difference_image,similarity_image);
1245 similarity_image=(Image *) NULL;
1250 case DotProductCorrelationErrorMetric:
1251 case NormalizedCrossCorrelationErrorMetric:
1253 distortion=1.0-distortion;
1254 similarity_metric=1.0-similarity_metric;
1257 case PhaseCorrelationErrorMetric:
1259 distortion=1.0-distortion;
1264 if (fabs(distortion) > CompareEpsilon)
1265 similar=MagickFalse;
1266 if (difference_image == (Image *) NULL)
1270 if (image_info->verbose != MagickFalse)
1271 (void) SetImageColorMetric(image,reconstruct_image,exception);
1272 if (*difference_image->magick ==
'\0')
1273 (void) CopyMagickString(difference_image->magick,image->magick,
1275 if (image_info->verbose == MagickFalse)
1279 case AbsoluteErrorMetric:
1280 case DotProductCorrelationErrorMetric:
1281 case FuzzErrorMetric:
1282 case NormalizedCrossCorrelationErrorMetric:
1283 case PerceptualHashErrorMetric:
1284 case PhaseCorrelationErrorMetric:
1285 case StructuralSimilarityErrorMetric:
1286 case StructuralDissimilarityErrorMetric:
1287 case MeanAbsoluteErrorMetric:
1288 case MeanSquaredErrorMetric:
1289 case PeakAbsoluteErrorMetric:
1290 case RootMeanSquaredErrorMetric:
1292 (void) FormatLocaleFile(stderr,
"%.*g (%.*g)",GetMagickPrecision(),
1293 (
double) QuantumRange*distortion,GetMagickPrecision(),
1297 case PeakSignalToNoiseRatioErrorMetric:
1299 (void) FormatLocaleFile(stderr,
"%.*g (%.*g)",GetMagickPrecision(),
1300 (
double) QuantumRange*distortion,GetMagickPrecision(),
1304 case MeanErrorPerPixelErrorMetric:
1306 (void) FormatLocaleFile(stderr,
"%.*g (%.*g, %.*g)",
1307 GetMagickPrecision(),distortion,
1308 GetMagickPrecision(),image->error.normalized_mean_error,
1309 GetMagickPrecision(),image->error.normalized_maximum_error);
1312 case UndefinedErrorMetric:
1315 if (subimage_search != MagickFalse)
1316 (void) FormatLocaleFile(stderr,
" @ %.20g,%.20g [%.*g]",
1317 (
double) difference_image->page.x,
1318 (
double) difference_image->page.y,GetMagickPrecision(),
1324 *channel_distortion;
1326 channel_distortion=GetImageDistortions(image,reconstruct_image,
1328 (void) FormatLocaleFile(stderr,
"Image: %s\n",image->filename);
1329 if ((reconstruct_image->columns != image->columns) ||
1330 (reconstruct_image->rows != image->rows))
1331 (void) FormatLocaleFile(stderr,
"Offset: %.20g,%.20g\n",(
double)
1332 difference_image->page.x,(
double) difference_image->page.y);
1333 (void) FormatLocaleFile(stderr,
" Channel distortion: %s\n",
1334 CommandOptionToMnemonic(MagickMetricOptions,(ssize_t) metric));
1337 case FuzzErrorMetric:
1338 case MeanAbsoluteErrorMetric:
1339 case MeanSquaredErrorMetric:
1340 case PeakAbsoluteErrorMetric:
1341 case RootMeanSquaredErrorMetric:
1343 switch (image->colorspace)
1348 (void) FormatLocaleFile(stderr,
" red: %.*g (%.*g)\n",
1349 GetMagickPrecision(),(
double) QuantumRange*
1350 channel_distortion[RedPixelChannel],GetMagickPrecision(),
1351 channel_distortion[RedPixelChannel]);
1352 (void) FormatLocaleFile(stderr,
" green: %.*g (%.*g)\n",
1353 GetMagickPrecision(),(
double) QuantumRange*
1354 channel_distortion[GreenPixelChannel],GetMagickPrecision(),
1355 channel_distortion[GreenPixelChannel]);
1356 (void) FormatLocaleFile(stderr,
" blue: %.*g (%.*g)\n",
1357 GetMagickPrecision(),(
double) QuantumRange*
1358 channel_distortion[BluePixelChannel],GetMagickPrecision(),
1359 channel_distortion[BluePixelChannel]);
1360 if (image->alpha_trait != UndefinedPixelTrait)
1361 (void) FormatLocaleFile(stderr,
" alpha: %.*g (%.*g)\n",
1362 GetMagickPrecision(),(
double) QuantumRange*
1363 channel_distortion[AlphaPixelChannel],
1364 GetMagickPrecision(),
1365 channel_distortion[AlphaPixelChannel]);
1368 case CMYKColorspace:
1370 (void) FormatLocaleFile(stderr,
" cyan: %.*g (%.*g)\n",
1371 GetMagickPrecision(),(
double) QuantumRange*
1372 channel_distortion[CyanPixelChannel],GetMagickPrecision(),
1373 channel_distortion[CyanPixelChannel]);
1374 (void) FormatLocaleFile(stderr,
" magenta: %.*g (%.*g)\n",
1375 GetMagickPrecision(),(
double) QuantumRange*
1376 channel_distortion[MagentaPixelChannel],
1377 GetMagickPrecision(),
1378 channel_distortion[MagentaPixelChannel]);
1379 (void) FormatLocaleFile(stderr,
" yellow: %.*g (%.*g)\n",
1380 GetMagickPrecision(),(
double) QuantumRange*
1381 channel_distortion[YellowPixelChannel],GetMagickPrecision(),
1382 channel_distortion[YellowPixelChannel]);
1383 (void) FormatLocaleFile(stderr,
" black: %.*g (%.*g)\n",
1384 GetMagickPrecision(),(
double) QuantumRange*
1385 channel_distortion[BlackPixelChannel],GetMagickPrecision(),
1386 channel_distortion[BlackPixelChannel]);
1387 if (image->alpha_trait != UndefinedPixelTrait)
1388 (void) FormatLocaleFile(stderr,
" alpha: %.*g (%.*g)\n",
1389 GetMagickPrecision(),(
double) QuantumRange*
1390 channel_distortion[AlphaPixelChannel],
1391 GetMagickPrecision(),
1392 channel_distortion[AlphaPixelChannel]);
1395 case LinearGRAYColorspace:
1396 case GRAYColorspace:
1398 (void) FormatLocaleFile(stderr,
" gray: %.*g (%.*g)\n",
1399 GetMagickPrecision(),(
double) QuantumRange*
1400 channel_distortion[GrayPixelChannel],GetMagickPrecision(),
1401 channel_distortion[GrayPixelChannel]);
1402 if (image->alpha_trait != UndefinedPixelTrait)
1403 (void) FormatLocaleFile(stderr,
" alpha: %.*g (%.*g)\n",
1404 GetMagickPrecision(),(
double) QuantumRange*
1405 channel_distortion[AlphaPixelChannel],
1406 GetMagickPrecision(),
1407 channel_distortion[AlphaPixelChannel]);
1411 (void) FormatLocaleFile(stderr,
" all: %.*g (%.*g)\n",
1412 GetMagickPrecision(),(
double) QuantumRange*
1413 channel_distortion[MaxPixelChannels],GetMagickPrecision(),
1414 channel_distortion[MaxPixelChannels]);
1417 case AbsoluteErrorMetric:
1418 case DotProductCorrelationErrorMetric:
1419 case NormalizedCrossCorrelationErrorMetric:
1420 case PeakSignalToNoiseRatioErrorMetric:
1421 case PerceptualHashErrorMetric:
1422 case PhaseCorrelationErrorMetric:
1423 case StructuralSimilarityErrorMetric:
1424 case StructuralDissimilarityErrorMetric:
1426 switch (image->colorspace)
1431 (void) FormatLocaleFile(stderr,
" red: %.*g\n",
1432 GetMagickPrecision(),channel_distortion[RedPixelChannel]);
1433 (void) FormatLocaleFile(stderr,
" green: %.*g\n",
1434 GetMagickPrecision(),channel_distortion[GreenPixelChannel]);
1435 (void) FormatLocaleFile(stderr,
" blue: %.*g\n",
1436 GetMagickPrecision(),channel_distortion[BluePixelChannel]);
1437 if (image->alpha_trait != UndefinedPixelTrait)
1438 (void) FormatLocaleFile(stderr,
" alpha: %.*g\n",
1439 GetMagickPrecision(),
1440 channel_distortion[AlphaPixelChannel]);
1443 case CMYKColorspace:
1445 (void) FormatLocaleFile(stderr,
" cyan: %.*g\n",
1446 GetMagickPrecision(),channel_distortion[CyanPixelChannel]);
1447 (void) FormatLocaleFile(stderr,
" magenta: %.*g\n",
1448 GetMagickPrecision(),
1449 channel_distortion[MagentaPixelChannel]);
1450 (void) FormatLocaleFile(stderr,
" yellow: %.*g\n",
1451 GetMagickPrecision(),
1452 channel_distortion[YellowPixelChannel]);
1453 (void) FormatLocaleFile(stderr,
" black: %.*g\n",
1454 GetMagickPrecision(),
1455 channel_distortion[BlackPixelChannel]);
1456 if (image->alpha_trait != UndefinedPixelTrait)
1457 (void) FormatLocaleFile(stderr,
" alpha: %.*g\n",
1458 GetMagickPrecision(),
1459 channel_distortion[AlphaPixelChannel]);
1462 case LinearGRAYColorspace:
1463 case GRAYColorspace:
1465 (void) FormatLocaleFile(stderr,
" gray: %.*g\n",
1466 GetMagickPrecision(),channel_distortion[GrayPixelChannel]);
1467 if (image->alpha_trait != UndefinedPixelTrait)
1468 (void) FormatLocaleFile(stderr,
" alpha: %.*g\n",
1469 GetMagickPrecision(),
1470 channel_distortion[AlphaPixelChannel]);
1474 (void) FormatLocaleFile(stderr,
" all: %.*g\n",
1475 GetMagickPrecision(),channel_distortion[MaxPixelChannels]);
1478 case MeanErrorPerPixelErrorMetric:
1480 (void) FormatLocaleFile(stderr,
" %.*g (%.*g, %.*g)\n",
1481 GetMagickPrecision(),channel_distortion[MaxPixelChannels],
1482 GetMagickPrecision(),image->error.normalized_mean_error,
1483 GetMagickPrecision(),image->error.normalized_maximum_error);
1486 case UndefinedErrorMetric:
1489 channel_distortion=(
double *) RelinquishMagickMemory(
1490 channel_distortion);
1491 if (subimage_search != MagickFalse)
1493 (void) FormatLocaleFile(stderr,
" Offset: %.20g,%.20g\n",(
double)
1494 difference_image->page.x,(
double) difference_image->page.y);
1495 (void) FormatLocaleFile(stderr,
" Similarity metric: %*g\n",
1496 GetMagickPrecision(),similarity_metric);
1499 (void) ResetImagePage(difference_image,
"0x0+0+0");
1500 if (difference_image->next != (Image *) NULL)
1501 (void) ResetImagePage(difference_image->next,
"0x0+0+0");
1502 status&=(MagickStatusType) WriteImages(image_info,difference_image,
1503 argv[argc-1],exception);
1504 if ((metadata != (
char **) NULL) && (format != (
char *) NULL))
1509 text=InterpretImageProperties(image_info,difference_image,format,
1511 if (text == (
char *) NULL)
1512 ThrowCompareException(ResourceLimitError,
"MemoryAllocationFailed",
1513 GetExceptionMessage(errno));
1514 (void) ConcatenateString(&(*metadata),text);
1515 text=DestroyString(text);
1517 difference_image=DestroyImageList(difference_image);
1520 if (similar == MagickFalse)
1521 (void) SetImageOption(image_info,
"compare:dissimilar",
"true");
1522 return(status != 0 ? MagickTrue : MagickFalse);