blob: 5dd5a1cef6c9ed15e86892ed910b7b6a15500f25 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% December 2003 %
18% %
19% %
Cristyf6ff9ea2016-12-05 09:53:35 -050020% Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% %
Cristyf19d4142017-04-24 11:34:30 -040026% https://www.imagemagick.org/script/license.php %
cristy3ed852e2009-09-05 21:47:34 +000027% %
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
cristy6a917d92009-10-06 19:23:54 +000037% difference between an image and its reconstruction.
cristy3ed852e2009-09-05 21:47:34 +000038%
39*/
40
41/*
42 Include declarations.
43*/
cristy4c08aed2011-07-01 19:47:50 +000044#include "MagickWand/studio.h"
45#include "MagickWand/MagickWand.h"
46#include "MagickWand/mogrify-private.h"
47#include "MagickCore/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000048
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%
cristy8a9106f2011-07-05 14:39:26 +000060% CompareImagesCommand() compares two images and returns the difference between
cristy3ed852e2009-09-05 21:47:34 +000061% them as a distortion metric and as a new image visually annotating their
62% differences.
63%
cristy8a9106f2011-07-05 14:39:26 +000064% The format of the CompareImagesCommand method is:
cristy3ed852e2009-09-05 21:47:34 +000065%
cristy8a9106f2011-07-05 14:39:26 +000066% MagickBooleanType CompareImagesCommand(ImageInfo *image_info,int argc,
cristy3ed852e2009-09-05 21:47:34 +000067% 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
83static MagickBooleanType CompareUsage(void)
84{
85 const char
86 **p;
87
88 static const char
89 *miscellaneous[]=
90 {
cristy17ada022014-11-07 22:12:23 +000091 "-channel mask set the image channel mask",
cristy3ed852e2009-09-05 21:47:34 +000092 "-debug events display copious debugging information",
93 "-help print program options",
94 "-list type print a list of supported option arguments",
95 "-log format format of debugging information",
96 (char *) NULL
97 },
Cristyf9ab5152017-05-16 21:05:26 -040098 *operators[]=
99 {
100 "-brightness-contrast geometry",
101 " improve brightness / contrast of the image",
102 "-distort method args",
Cristy002b27d2017-05-16 21:13:16 -0400103 " distort images according to given method and args",
Cristyf9ab5152017-05-16 21:05:26 -0400104 "-level value adjust the level of image contrast",
105 "-resize geometry resize the image",
106 "-rotate degrees apply Paeth rotation to the image",
107 "-sigmoidal-contrast geometry",
108 " increase the contrast without saturating highlights or",
Cristycd1c5272017-05-16 21:11:13 -0400109 "-trim trim image edges",
110 (char *) NULL
Cristyf9ab5152017-05-16 21:05:26 -0400111 },
112 *sequence_operators[]=
113 {
Cristycd1c5272017-05-16 21:11:13 -0400114 "-crop geometry cut out a rectangular region of the image",
115 (char *) NULL
Cristyf9ab5152017-05-16 21:05:26 -0400116 },
cristy3ed852e2009-09-05 21:47:34 +0000117 *settings[]=
118 {
119 "-alpha option on, activate, off, deactivate, set, opaque, copy",
120 " transparent, extract, background, or shape",
121 "-authenticate password",
122 " decipher image with this password",
Cristy63571f72017-05-17 15:11:19 -0400123 "-background color background color",
cristy3ed852e2009-09-05 21:47:34 +0000124 "-colorspace type alternate image colorspace",
125 "-compose operator set image composite operator",
126 "-compress type type of pixel compression when writing the image",
127 "-decipher filename convert cipher pixels to plain pixels",
128 "-define format:option",
129 " define one or more image format options",
130 "-density geometry horizontal and vertical density of the image",
131 "-depth value image depth",
132 "-dissimilarity-threshold value",
cristyba029a52010-11-27 02:18:26 +0000133 " maximum distortion for (sub)image match",
cristy3ed852e2009-09-05 21:47:34 +0000134 "-encipher filename convert plain pixels to cipher pixels",
135 "-extract geometry extract area from image",
136 "-format \"string\" output formatted image characteristics",
137 "-fuzz distance colors within this distance are considered equal",
138 "-highlight-color color",
139 " empasize pixel differences with this color",
140 "-identify identify the format and characteristics of the image",
141 "-interlace type type of image interlacing scheme",
142 "-limit type value pixel cache resource limit",
143 "-lowlight-color color",
144 " de-emphasize pixel differences with this color",
145 "-metric type measure differences between images with this metric",
146 "-monitor monitor progress",
Cristy6e6ce012016-11-26 19:00:03 -0500147 "-negate replace every pixel with its complementary color ",
cristy3ed852e2009-09-05 21:47:34 +0000148 "-profile filename add, delete, or apply an image profile",
149 "-quality value JPEG/MIFF/PNG compression level",
150 "-quiet suppress all warning messages",
151 "-quantize colorspace reduce colors in this colorspace",
Cristy55d3c442016-12-02 19:46:34 -0500152 "-read-mask filename associate a read mask with the image",
cristy3ed852e2009-09-05 21:47:34 +0000153 "-regard-warnings pay attention to warning messages",
154 "-respect-parentheses settings remain in effect until parenthesis boundary",
155 "-sampling-factor geometry",
156 " horizontal and vertical sampling factor",
157 "-seed value seed a new sequence of pseudo-random numbers",
158 "-set attribute value set an image attribute",
159 "-quality value JPEG/MIFF/PNG compression level",
Cristyd9589b12017-05-19 07:12:51 -0400160 "-repage geometry size and location of an image canvas",
cristy0ad4ab22013-03-15 01:14:59 +0000161 "-similarity-threshold value",
162 " minimum distortion for (sub)image match",
cristy3ed852e2009-09-05 21:47:34 +0000163 "-size geometry width and height of image",
cristyb9498042010-08-09 01:14:07 +0000164 "-subimage-search search for subimage",
cristye9252c22013-07-30 15:43:21 +0000165 "-synchronize synchronize image to storage device",
166 "-taint declare the image as modified",
cristy3ed852e2009-09-05 21:47:34 +0000167 "-transparent-color color",
168 " transparent color",
169 "-type type image type",
170 "-verbose print detailed information about the image",
171 "-version print version information",
172 "-virtual-pixel method",
173 " virtual pixel access method",
Cristy55d3c442016-12-02 19:46:34 -0500174 "-write-mask filename associate a write mask with the image",
cristy3ed852e2009-09-05 21:47:34 +0000175 (char *) NULL
176 };
177
cristy4f7a6132012-12-23 00:35:19 +0000178 ListMagickVersion(stdout);
cristy3ed852e2009-09-05 21:47:34 +0000179 (void) printf("Usage: %s [options ...] image reconstruct difference\n",
180 GetClientName());
181 (void) printf("\nImage Settings:\n");
182 for (p=settings; *p != (char *) NULL; p++)
183 (void) printf(" %s\n",*p);
Cristyf9ab5152017-05-16 21:05:26 -0400184 (void) printf("\nImage Operators:\n");
185 for (p=operators; *p != (char *) NULL; p++)
186 (void) printf(" %s\n",*p);
187 (void) printf("\nImage Sequence Operators:\n");
188 for (p=sequence_operators; *p != (char *) NULL; p++)
189 (void) printf(" %s\n",*p);
cristy3ed852e2009-09-05 21:47:34 +0000190 (void) printf("\nMiscellaneous Options:\n");
191 for (p=miscellaneous; *p != (char *) NULL; p++)
192 (void) printf(" %s\n",*p);
193 (void) printf(
anthonye5b39652012-04-21 05:37:29 +0000194 "\nBy default, the image format of 'file' is determined by its magic\n");
cristy3ed852e2009-09-05 21:47:34 +0000195 (void) printf(
196 "number. To specify a particular image format, precede the filename\n");
197 (void) printf(
198 "with an image format name and a colon (i.e. ps:image) or specify the\n");
199 (void) printf(
200 "image type as the filename suffix (i.e. image.ps). Specify 'file' as\n");
201 (void) printf("'-' for standard input or output.\n");
202 return(MagickFalse);
203}
204
cristy8a9106f2011-07-05 14:39:26 +0000205WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info,
cristy3ed852e2009-09-05 21:47:34 +0000206 int argc,char **argv,char **metadata,ExceptionInfo *exception)
207{
cristy2cb55d52013-07-10 22:20:51 +0000208#define CompareEpsilon (1.0e-06)
cristy2b70e802009-11-23 19:40:25 +0000209#define DefaultDissimilarityThreshold 0.31830988618379067154
cristy7691e472013-04-28 01:48:12 +0000210#define DefaultSimilarityThreshold (-1.0)
cristy3ed852e2009-09-05 21:47:34 +0000211#define DestroyCompare() \
212{ \
213 if (similarity_image != (Image *) NULL) \
214 similarity_image=DestroyImageList(similarity_image); \
215 if (difference_image != (Image *) NULL) \
216 difference_image=DestroyImageList(difference_image); \
217 DestroyImageStack(); \
cristybb503372010-05-27 20:51:26 +0000218 for (i=0; i < (ssize_t) argc; i++) \
cristy3ed852e2009-09-05 21:47:34 +0000219 argv[i]=DestroyString(argv[i]); \
220 argv=(char **) RelinquishMagickMemory(argv); \
221}
222#define ThrowCompareException(asperity,tag,option) \
223{ \
224 if (exception->severity < (asperity)) \
225 (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
cristyefe601c2013-01-05 17:51:12 +0000226 "`%s'",option); \
cristy3ed852e2009-09-05 21:47:34 +0000227 DestroyCompare(); \
228 return(MagickFalse); \
229}
230#define ThrowCompareInvalidArgumentException(option,argument) \
231{ \
232 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
anthonye5b39652012-04-21 05:37:29 +0000233 "InvalidArgument","'%s': %s",option,argument); \
cristy3ed852e2009-09-05 21:47:34 +0000234 DestroyCompare(); \
235 return(MagickFalse); \
236}
237
238 char
239 *filename,
240 *option;
241
242 const char
243 *format;
244
cristy3ed852e2009-09-05 21:47:34 +0000245 double
246 dissimilarity_threshold,
247 distortion,
cristy4dab3802013-03-15 22:08:15 +0000248 similarity_metric,
249 similarity_threshold;
cristy3ed852e2009-09-05 21:47:34 +0000250
251 Image
252 *difference_image,
253 *image,
254 *reconstruct_image,
255 *similarity_image;
256
257 ImageStack
258 image_stack[MaxImageStackDepth+1];
259
cristy3ed852e2009-09-05 21:47:34 +0000260 MagickBooleanType
261 fire,
cristyae6203d2010-08-09 01:12:14 +0000262 pend,
cristyebbcfea2011-02-25 02:43:54 +0000263 respect_parenthesis,
cristyae6203d2010-08-09 01:12:14 +0000264 subimage_search;
cristy3ed852e2009-09-05 21:47:34 +0000265
266 MagickStatusType
267 status;
268
269 MetricType
270 metric;
271
272 RectangleInfo
273 offset;
274
cristybb503372010-05-27 20:51:26 +0000275 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000276 i;
277
cristyae6203d2010-08-09 01:12:14 +0000278 ssize_t
279 j,
280 k;
281
cristy3ed852e2009-09-05 21:47:34 +0000282 /*
283 Set defaults.
284 */
285 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000286 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000287 if (image_info->debug != MagickFalse)
288 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
289 assert(exception != (ExceptionInfo *) NULL);
290 if (argc == 2)
291 {
292 option=argv[1];
293 if ((LocaleCompare("version",option+1) == 0) ||
294 (LocaleCompare("-version",option+1) == 0))
295 {
cristy4f7a6132012-12-23 00:35:19 +0000296 ListMagickVersion(stdout);
Cristydf0b2912016-05-17 16:00:28 -0400297 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000298 }
299 }
300 if (argc < 3)
cristy13e61a12010-02-04 20:19:00 +0000301 return(CompareUsage());
cristy3ed852e2009-09-05 21:47:34 +0000302 difference_image=NewImageList();
303 similarity_image=NewImageList();
304 dissimilarity_threshold=DefaultDissimilarityThreshold;
cristy62e52182013-03-15 14:26:17 +0000305 similarity_threshold=DefaultSimilarityThreshold;
cristy3ed852e2009-09-05 21:47:34 +0000306 distortion=0.0;
307 format=(char *) NULL;
308 j=1;
309 k=0;
cristy2cb55d52013-07-10 22:20:51 +0000310 metric=UndefinedErrorMetric;
cristy3ed852e2009-09-05 21:47:34 +0000311 NewImageStack();
312 option=(char *) NULL;
313 pend=MagickFalse;
314 reconstruct_image=NewImageList();
cristyebbcfea2011-02-25 02:43:54 +0000315 respect_parenthesis=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000316 status=MagickTrue;
cristyae6203d2010-08-09 01:12:14 +0000317 subimage_search=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000318 /*
319 Compare an image.
320 */
321 ReadCommandlLine(argc,&argv);
322 status=ExpandFilenames(&argc,&argv);
323 if (status == MagickFalse)
324 ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
325 GetExceptionMessage(errno));
cristybb503372010-05-27 20:51:26 +0000326 for (i=1; i < (ssize_t) (argc-1); i++)
cristy3ed852e2009-09-05 21:47:34 +0000327 {
328 option=argv[i];
329 if (LocaleCompare(option,"(") == 0)
330 {
331 FireImageStack(MagickTrue,MagickTrue,pend);
332 if (k == MaxImageStackDepth)
333 ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply",
334 option);
335 PushImageStack();
336 continue;
337 }
338 if (LocaleCompare(option,")") == 0)
339 {
340 FireImageStack(MagickTrue,MagickTrue,MagickTrue);
341 if (k == 0)
342 ThrowCompareException(OptionError,"UnableToParseExpression",option);
343 PopImageStack();
344 continue;
345 }
cristy042ee782011-04-22 18:48:30 +0000346 if (IsCommandOption(option) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000347 {
348 Image
349 *images;
350
351 /*
352 Read input image.
353 */
354 FireImageStack(MagickFalse,MagickFalse,pend);
355 filename=argv[i];
cristycee97112010-05-28 00:44:52 +0000356 if ((LocaleCompare(filename,"--") == 0) && (i < (ssize_t) (argc-1)))
cristy3ed852e2009-09-05 21:47:34 +0000357 filename=argv[++i];
cristy1b58f252012-03-01 01:41:41 +0000358 images=ReadImages(image_info,filename,exception);
cristy3ed852e2009-09-05 21:47:34 +0000359 status&=(images != (Image *) NULL) &&
360 (exception->severity < ErrorException);
361 if (images == (Image *) NULL)
362 continue;
363 AppendImageStack(images);
364 continue;
365 }
366 pend=image != (Image *) NULL ? MagickTrue : MagickFalse;
367 switch (*(option+1))
368 {
369 case 'a':
370 {
371 if (LocaleCompare("alpha",option+1) == 0)
372 {
cristybb503372010-05-27 20:51:26 +0000373 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000374 type;
375
376 if (*option == '+')
377 break;
378 i++;
cristybb503372010-05-27 20:51:26 +0000379 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000380 ThrowCompareException(OptionError,"MissingArgument",option);
Cristyf9ab5152017-05-16 21:05:26 -0400381 type=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,
382 argv[i]);
cristy3ed852e2009-09-05 21:47:34 +0000383 if (type < 0)
Cristyf9ab5152017-05-16 21:05:26 -0400384 ThrowCompareException(OptionError,
385 "UnrecognizedAlphaChannelOption",argv[i]);
cristy3ed852e2009-09-05 21:47:34 +0000386 break;
387 }
388 if (LocaleCompare("authenticate",option+1) == 0)
389 {
390 if (*option == '+')
391 break;
392 i++;
cristybb503372010-05-27 20:51:26 +0000393 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000394 ThrowCompareException(OptionError,"MissingArgument",option);
395 break;
396 }
397 ThrowCompareException(OptionError,"UnrecognizedOption",option);
398 }
Cristyf9ab5152017-05-16 21:05:26 -0400399 case 'b':
400 {
Cristy63571f72017-05-17 15:11:19 -0400401 if (LocaleCompare("background",option+1) == 0)
402 {
403 if (*option == '+')
404 break;
405 i++;
406 if (i == (ssize_t) argc)
407 ThrowCompareException(OptionError,"MissingArgument",option);
408 break;
409 }
Cristyf9ab5152017-05-16 21:05:26 -0400410 if (LocaleCompare("brightness-contrast",option+1) == 0)
411 {
412 i++;
413 if (i == (ssize_t) argc)
414 ThrowCompareException(OptionError,"MissingArgument",option);
415 if (IsGeometry(argv[i]) == MagickFalse)
416 ThrowCompareInvalidArgumentException(option,argv[i]);
417 break;
418 }
419 ThrowCompareException(OptionError,"UnrecognizedOption",option);
420 }
cristy3ed852e2009-09-05 21:47:34 +0000421 case 'c':
422 {
423 if (LocaleCompare("cache",option+1) == 0)
424 {
425 if (*option == '+')
426 break;
427 i++;
cristybb503372010-05-27 20:51:26 +0000428 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000429 ThrowCompareException(OptionError,"MissingArgument",option);
430 if (IsGeometry(argv[i]) == MagickFalse)
431 ThrowCompareInvalidArgumentException(option,argv[i]);
432 break;
433 }
434 if (LocaleCompare("channel",option+1) == 0)
435 {
cristybb503372010-05-27 20:51:26 +0000436 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000437 channel;
438
439 if (*option == '+')
440 break;
441 i++;
cristye81f5522014-05-07 01:25:59 +0000442 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000443 ThrowCompareException(OptionError,"MissingArgument",option);
444 channel=ParseChannelOption(argv[i]);
445 if (channel < 0)
446 ThrowCompareException(OptionError,"UnrecognizedChannelType",
447 argv[i]);
cristy3ed852e2009-09-05 21:47:34 +0000448 break;
449 }
450 if (LocaleCompare("colorspace",option+1) == 0)
451 {
cristybb503372010-05-27 20:51:26 +0000452 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000453 colorspace;
454
455 if (*option == '+')
456 break;
457 i++;
cristye81f5522014-05-07 01:25:59 +0000458 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000459 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +0000460 colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000461 argv[i]);
462 if (colorspace < 0)
463 ThrowCompareException(OptionError,"UnrecognizedColorspace",
464 argv[i]);
465 break;
466 }
467 if (LocaleCompare("compose",option+1) == 0)
468 {
cristybb503372010-05-27 20:51:26 +0000469 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000470 compose;
471
472 if (*option == '+')
473 break;
474 i++;
cristybb503372010-05-27 20:51:26 +0000475 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000476 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +0000477 compose=ParseCommandOption(MagickComposeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000478 argv[i]);
479 if (compose < 0)
480 ThrowCompareException(OptionError,"UnrecognizedComposeOperator",
481 argv[i]);
482 break;
483 }
484 if (LocaleCompare("compress",option+1) == 0)
485 {
cristybb503372010-05-27 20:51:26 +0000486 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000487 compress;
488
489 if (*option == '+')
490 break;
491 i++;
cristye81f5522014-05-07 01:25:59 +0000492 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000493 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +0000494 compress=ParseCommandOption(MagickCompressOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000495 argv[i]);
496 if (compress < 0)
497 ThrowCompareException(OptionError,"UnrecognizedImageCompression",
498 argv[i]);
499 break;
500 }
cristy22879752009-10-25 23:55:40 +0000501 if (LocaleCompare("concurrent",option+1) == 0)
502 break;
Cristyf9ab5152017-05-16 21:05:26 -0400503 if (LocaleCompare("crop",option+1) == 0)
504 {
505 if (*option == '+')
506 break;
507 i++;
508 if (i == (ssize_t) argc)
509 ThrowCompareException(OptionError,"MissingArgument",option);
510 if (IsGeometry(argv[i]) == MagickFalse)
511 ThrowCompareInvalidArgumentException(option,argv[i]);
512 break;
513 }
cristy3ed852e2009-09-05 21:47:34 +0000514 ThrowCompareException(OptionError,"UnrecognizedOption",option)
515 }
516 case 'd':
517 {
518 if (LocaleCompare("debug",option+1) == 0)
519 {
520 LogEventType
521 event_mask;
522
523 if (*option == '+')
524 break;
525 i++;
cristybb503372010-05-27 20:51:26 +0000526 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000527 ThrowCompareException(OptionError,"MissingArgument",option);
528 event_mask=SetLogEventMask(argv[i]);
529 if (event_mask == UndefinedEvents)
530 ThrowCompareException(OptionError,"UnrecognizedEventType",
531 argv[i]);
532 break;
533 }
534 if (LocaleCompare("decipher",option+1) == 0)
535 {
536 if (*option == '+')
537 break;
538 i++;
cristye81f5522014-05-07 01:25:59 +0000539 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000540 ThrowCompareException(OptionError,"MissingArgument",option);
541 break;
542 }
543 if (LocaleCompare("define",option+1) == 0)
544 {
545 i++;
cristybb503372010-05-27 20:51:26 +0000546 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000547 ThrowCompareException(OptionError,"MissingArgument",option);
548 if (*option == '+')
549 {
550 const char
551 *define;
552
553 define=GetImageOption(image_info,argv[i]);
554 if (define == (const char *) NULL)
555 ThrowCompareException(OptionError,"NoSuchOption",argv[i]);
556 break;
557 }
558 break;
559 }
560 if (LocaleCompare("density",option+1) == 0)
561 {
562 if (*option == '+')
563 break;
564 i++;
cristybb503372010-05-27 20:51:26 +0000565 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000566 ThrowCompareException(OptionError,"MissingArgument",option);
567 if (IsGeometry(argv[i]) == MagickFalse)
568 ThrowCompareInvalidArgumentException(option,argv[i]);
569 break;
570 }
571 if (LocaleCompare("depth",option+1) == 0)
572 {
573 if (*option == '+')
574 break;
575 i++;
cristybb503372010-05-27 20:51:26 +0000576 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000577 ThrowCompareException(OptionError,"MissingArgument",option);
578 if (IsGeometry(argv[i]) == MagickFalse)
579 ThrowCompareInvalidArgumentException(option,argv[i]);
580 break;
581 }
582 if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
583 {
584 if (*option == '+')
585 break;
586 i++;
cristybb503372010-05-27 20:51:26 +0000587 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000588 ThrowCompareException(OptionError,"MissingArgument",option);
589 if (IsGeometry(argv[i]) == MagickFalse)
590 ThrowCompareInvalidArgumentException(option,argv[i]);
591 if (*option == '+')
592 dissimilarity_threshold=DefaultDissimilarityThreshold;
593 else
cristy9b34e302011-11-05 02:15:45 +0000594 dissimilarity_threshold=StringToDouble(argv[i],(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000595 break;
596 }
Cristyf9ab5152017-05-16 21:05:26 -0400597 if (LocaleCompare("distort",option+1) == 0)
598 {
599 ssize_t
600 op;
601
602 i++;
603 if (i == (ssize_t) argc)
604 ThrowCompareException(OptionError,"MissingArgument",option);
605 op=ParseCommandOption(MagickDistortOptions,MagickFalse,argv[i]);
606 if (op < 0)
607 ThrowCompareException(OptionError,"UnrecognizedDistortMethod",
608 argv[i]);
609 i++;
610 if (i == (ssize_t) argc)
611 ThrowCompareException(OptionError,"MissingArgument",option);
612 break;
613 }
cristy22879752009-10-25 23:55:40 +0000614 if (LocaleCompare("duration",option+1) == 0)
615 {
616 if (*option == '+')
617 break;
618 i++;
cristye81f5522014-05-07 01:25:59 +0000619 if (i == (ssize_t) argc)
cristy22879752009-10-25 23:55:40 +0000620 ThrowCompareException(OptionError,"MissingArgument",option);
621 if (IsGeometry(argv[i]) == MagickFalse)
622 ThrowCompareInvalidArgumentException(option,argv[i]);
623 break;
624 }
cristy3ed852e2009-09-05 21:47:34 +0000625 ThrowCompareException(OptionError,"UnrecognizedOption",option)
626 }
627 case 'e':
628 {
629 if (LocaleCompare("encipher",option+1) == 0)
630 {
631 if (*option == '+')
632 break;
633 i++;
cristye81f5522014-05-07 01:25:59 +0000634 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000635 ThrowCompareException(OptionError,"MissingArgument",option);
636 break;
637 }
638 if (LocaleCompare("extract",option+1) == 0)
639 {
640 if (*option == '+')
641 break;
642 i++;
cristye81f5522014-05-07 01:25:59 +0000643 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000644 ThrowCompareException(OptionError,"MissingArgument",option);
645 if (IsGeometry(argv[i]) == MagickFalse)
646 ThrowCompareInvalidArgumentException(option,argv[i]);
647 break;
648 }
649 ThrowCompareException(OptionError,"UnrecognizedOption",option)
650 }
651 case 'f':
652 {
653 if (LocaleCompare("format",option+1) == 0)
654 {
655 if (*option == '+')
656 break;
657 i++;
cristybb503372010-05-27 20:51:26 +0000658 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000659 ThrowCompareException(OptionError,"MissingArgument",option);
660 format=argv[i];
661 break;
662 }
663 if (LocaleCompare("fuzz",option+1) == 0)
664 {
665 if (*option == '+')
666 break;
667 i++;
cristye81f5522014-05-07 01:25:59 +0000668 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000669 ThrowCompareException(OptionError,"MissingArgument",option);
670 if (IsGeometry(argv[i]) == MagickFalse)
671 ThrowCompareInvalidArgumentException(option,argv[i]);
672 break;
673 }
674 ThrowCompareException(OptionError,"UnrecognizedOption",option)
675 }
676 case 'h':
677 {
678 if ((LocaleCompare("help",option+1) == 0) ||
679 (LocaleCompare("-help",option+1) == 0))
680 return(CompareUsage());
681 if (LocaleCompare("highlight-color",option+1) == 0)
682 {
683 if (*option == '+')
684 break;
685 i++;
cristye81f5522014-05-07 01:25:59 +0000686 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000687 ThrowCompareException(OptionError,"MissingArgument",option);
688 break;
689 }
690 ThrowCompareException(OptionError,"UnrecognizedOption",option)
691 }
692 case 'i':
693 {
694 if (LocaleCompare("identify",option+1) == 0)
695 break;
696 if (LocaleCompare("interlace",option+1) == 0)
697 {
cristybb503372010-05-27 20:51:26 +0000698 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000699 interlace;
700
701 if (*option == '+')
702 break;
703 i++;
cristybb503372010-05-27 20:51:26 +0000704 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000705 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +0000706 interlace=ParseCommandOption(MagickInterlaceOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000707 argv[i]);
708 if (interlace < 0)
709 ThrowCompareException(OptionError,"UnrecognizedInterlaceType",
710 argv[i]);
711 break;
712 }
713 ThrowCompareException(OptionError,"UnrecognizedOption",option)
714 }
715 case 'l':
716 {
Cristyf9ab5152017-05-16 21:05:26 -0400717 if (LocaleCompare("level",option+1) == 0)
718 {
719 i++;
720 if (i == (ssize_t) argc)
721 ThrowCompareException(OptionError,"MissingArgument",option);
722 if (IsGeometry(argv[i]) == MagickFalse)
723 ThrowCompareInvalidArgumentException(option,argv[i]);
724 break;
725 }
cristy3ed852e2009-09-05 21:47:34 +0000726 if (LocaleCompare("limit",option+1) == 0)
727 {
728 char
729 *p;
730
731 double
732 value;
733
cristybb503372010-05-27 20:51:26 +0000734 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000735 resource;
736
737 if (*option == '+')
738 break;
739 i++;
cristybb503372010-05-27 20:51:26 +0000740 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000741 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +0000742 resource=ParseCommandOption(MagickResourceOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000743 argv[i]);
744 if (resource < 0)
745 ThrowCompareException(OptionError,"UnrecognizedResourceType",
746 argv[i]);
747 i++;
cristybb503372010-05-27 20:51:26 +0000748 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000749 ThrowCompareException(OptionError,"MissingArgument",option);
cristydbdd0e32011-11-04 23:29:40 +0000750 value=StringToDouble(argv[i],&p);
cristyda16f162011-02-19 23:52:17 +0000751 (void) value;
cristy3ed852e2009-09-05 21:47:34 +0000752 if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0))
753 ThrowCompareInvalidArgumentException(option,argv[i]);
754 break;
755 }
756 if (LocaleCompare("list",option+1) == 0)
757 {
cristybb503372010-05-27 20:51:26 +0000758 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000759 list;
760
761 if (*option == '+')
762 break;
763 i++;
cristybb503372010-05-27 20:51:26 +0000764 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000765 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +0000766 list=ParseCommandOption(MagickListOptions,MagickFalse,argv[i]);
cristy3ed852e2009-09-05 21:47:34 +0000767 if (list < 0)
768 ThrowCompareException(OptionError,"UnrecognizedListType",argv[i]);
cristyaeb2cbc2010-05-07 13:28:58 +0000769 status=MogrifyImageInfo(image_info,(int) (i-j+1),(const char **)
cristy3ed852e2009-09-05 21:47:34 +0000770 argv+j,exception);
771 DestroyCompare();
cristy32ce2392014-09-24 19:08:53 +0000772 return(status == 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000773 }
774 if (LocaleCompare("log",option+1) == 0)
775 {
776 if (*option == '+')
777 break;
778 i++;
cristybb503372010-05-27 20:51:26 +0000779 if ((i == (ssize_t) argc) || (strchr(argv[i],'%') == (char *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000780 ThrowCompareException(OptionError,"MissingArgument",option);
781 break;
782 }
783 if (LocaleCompare("lowlight-color",option+1) == 0)
784 {
785 if (*option == '+')
786 break;
787 i++;
cristye81f5522014-05-07 01:25:59 +0000788 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000789 ThrowCompareException(OptionError,"MissingArgument",option);
790 break;
791 }
792 ThrowCompareException(OptionError,"UnrecognizedOption",option)
793 }
794 case 'm':
795 {
796 if (LocaleCompare("matte",option+1) == 0)
797 break;
798 if (LocaleCompare("metric",option+1) == 0)
799 {
cristybb503372010-05-27 20:51:26 +0000800 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000801 type;
802
803 if (*option == '+')
804 break;
805 i++;
cristybb503372010-05-27 20:51:26 +0000806 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000807 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +0000808 type=ParseCommandOption(MagickMetricOptions,MagickTrue,argv[i]);
cristy3ed852e2009-09-05 21:47:34 +0000809 if (type < 0)
810 ThrowCompareException(OptionError,"UnrecognizedMetricType",
811 argv[i]);
812 metric=(MetricType) type;
813 break;
814 }
815 if (LocaleCompare("monitor",option+1) == 0)
816 break;
817 ThrowCompareException(OptionError,"UnrecognizedOption",option)
818 }
Cristy6e6ce012016-11-26 19:00:03 -0500819 case 'n':
820 {
821 if (LocaleCompare("negate",option+1) == 0)
822 break;
823 ThrowCompareException(OptionError,"UnrecognizedOption",option)
824 }
cristy3ed852e2009-09-05 21:47:34 +0000825 case 'p':
826 {
cristy3ed852e2009-09-05 21:47:34 +0000827 if (LocaleCompare("profile",option+1) == 0)
828 {
829 i++;
cristye81f5522014-05-07 01:25:59 +0000830 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000831 ThrowCompareException(OptionError,"MissingArgument",option);
832 break;
833 }
834 ThrowCompareException(OptionError,"UnrecognizedOption",option)
835 }
836 case 'q':
837 {
838 if (LocaleCompare("quality",option+1) == 0)
839 {
840 if (*option == '+')
841 break;
842 i++;
cristye81f5522014-05-07 01:25:59 +0000843 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000844 ThrowCompareException(OptionError,"MissingArgument",option);
845 if (IsGeometry(argv[i]) == MagickFalse)
846 ThrowCompareInvalidArgumentException(option,argv[i]);
847 break;
848 }
849 if (LocaleCompare("quantize",option+1) == 0)
850 {
cristybb503372010-05-27 20:51:26 +0000851 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000852 colorspace;
853
854 if (*option == '+')
855 break;
856 i++;
cristye81f5522014-05-07 01:25:59 +0000857 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000858 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +0000859 colorspace=ParseCommandOption(MagickColorspaceOptions,
cristy3ed852e2009-09-05 21:47:34 +0000860 MagickFalse,argv[i]);
861 if (colorspace < 0)
862 ThrowCompareException(OptionError,"UnrecognizedColorspace",
863 argv[i]);
864 break;
865 }
866 if (LocaleCompare("quiet",option+1) == 0)
867 break;
868 ThrowCompareException(OptionError,"UnrecognizedOption",option)
869 }
870 case 'r':
871 {
Cristy756a4472016-11-26 09:17:41 -0500872 if (LocaleCompare("read-mask",option+1) == 0)
873 {
874 if (*option == '+')
875 break;
876 i++;
877 if (i == (ssize_t) argc)
878 ThrowCompareException(OptionError,"MissingArgument",option);
879 break;
880 }
cristy3ed852e2009-09-05 21:47:34 +0000881 if (LocaleCompare("regard-warnings",option+1) == 0)
882 break;
Cristyd9589b12017-05-19 07:12:51 -0400883 if (LocaleCompare("repage",option+1) == 0)
884 {
885 if (*option == '+')
886 break;
887 i++;
888 if (i == (ssize_t) argc)
889 ThrowCompareException(OptionError,"MissingArgument",option);
890 if (IsGeometry(argv[i]) == MagickFalse)
891 ThrowCompareInvalidArgumentException(option,argv[i]);
892 break;
893 }
Cristyf9ab5152017-05-16 21:05:26 -0400894 if (LocaleCompare("resize",option+1) == 0)
895 {
896 if (*option == '+')
897 break;
898 i++;
899 if (i == (ssize_t) argc)
900 ThrowCompareException(OptionError,"MissingArgument",option);
901 if (IsGeometry(argv[i]) == MagickFalse)
902 ThrowCompareInvalidArgumentException(option,argv[i]);
903 break;
904 }
cristy3ed852e2009-09-05 21:47:34 +0000905 if (LocaleNCompare("respect-parentheses",option+1,17) == 0)
906 {
907 respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse;
908 break;
909 }
Cristyf9ab5152017-05-16 21:05:26 -0400910 if (LocaleCompare("rotate",option+1) == 0)
911 {
912 i++;
913 if (i == (ssize_t) argc)
914 ThrowCompareException(OptionError,"MissingArgument",option);
915 if (IsGeometry(argv[i]) == MagickFalse)
916 ThrowCompareInvalidArgumentException(option,argv[i]);
917 break;
918 }
cristy3ed852e2009-09-05 21:47:34 +0000919 ThrowCompareException(OptionError,"UnrecognizedOption",option)
920 }
921 case 's':
922 {
923 if (LocaleCompare("sampling-factor",option+1) == 0)
924 {
925 if (*option == '+')
926 break;
927 i++;
cristybb503372010-05-27 20:51:26 +0000928 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000929 ThrowCompareException(OptionError,"MissingArgument",option);
930 if (IsGeometry(argv[i]) == MagickFalse)
931 ThrowCompareInvalidArgumentException(option,argv[i]);
932 break;
933 }
934 if (LocaleCompare("seed",option+1) == 0)
935 {
936 if (*option == '+')
937 break;
938 i++;
cristye81f5522014-05-07 01:25:59 +0000939 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000940 ThrowCompareException(OptionError,"MissingArgument",option);
941 if (IsGeometry(argv[i]) == MagickFalse)
942 ThrowCompareInvalidArgumentException(option,argv[i]);
943 break;
944 }
945 if (LocaleCompare("set",option+1) == 0)
946 {
947 i++;
cristybb503372010-05-27 20:51:26 +0000948 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000949 ThrowCompareException(OptionError,"MissingArgument",option);
950 if (*option == '+')
951 break;
952 i++;
cristybb503372010-05-27 20:51:26 +0000953 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000954 ThrowCompareException(OptionError,"MissingArgument",option);
955 break;
956 }
Cristyf9ab5152017-05-16 21:05:26 -0400957 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
958 {
959 i++;
960 if (i == (ssize_t) argc)
961 ThrowCompareException(OptionError,"MissingArgument",option);
962 if (IsGeometry(argv[i]) == MagickFalse)
963 ThrowCompareInvalidArgumentException(option,argv[i]);
964 break;
965 }
cristy62e52182013-03-15 14:26:17 +0000966 if (LocaleCompare("similarity-threshold",option+1) == 0)
967 {
968 if (*option == '+')
969 break;
970 i++;
971 if (i == (ssize_t) argc)
972 ThrowCompareException(OptionError,"MissingArgument",option);
973 if (IsGeometry(argv[i]) == MagickFalse)
974 ThrowCompareInvalidArgumentException(option,argv[i]);
975 if (*option == '+')
976 similarity_threshold=DefaultSimilarityThreshold;
977 else
978 similarity_threshold=StringToDouble(argv[i],(char **) NULL);
979 break;
980 }
cristy3ed852e2009-09-05 21:47:34 +0000981 if (LocaleCompare("size",option+1) == 0)
982 {
983 if (*option == '+')
984 break;
985 i++;
cristybb503372010-05-27 20:51:26 +0000986 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +0000987 ThrowCompareException(OptionError,"MissingArgument",option);
988 if (IsGeometry(argv[i]) == MagickFalse)
989 ThrowCompareInvalidArgumentException(option,argv[i]);
990 break;
991 }
cristyae6203d2010-08-09 01:12:14 +0000992 if (LocaleCompare("subimage-search",option+1) == 0)
993 {
994 if (*option == '+')
995 {
996 subimage_search=MagickFalse;
997 break;
998 }
999 subimage_search=MagickTrue;
1000 break;
1001 }
cristyd9a29192010-10-16 16:49:53 +00001002 if (LocaleCompare("synchronize",option+1) == 0)
1003 break;
cristy3ed852e2009-09-05 21:47:34 +00001004 ThrowCompareException(OptionError,"UnrecognizedOption",option)
1005 }
1006 case 't':
1007 {
cristyd9a29192010-10-16 16:49:53 +00001008 if (LocaleCompare("taint",option+1) == 0)
1009 break;
cristy3ed852e2009-09-05 21:47:34 +00001010 if (LocaleCompare("transparent-color",option+1) == 0)
1011 {
1012 if (*option == '+')
1013 break;
1014 i++;
cristye81f5522014-05-07 01:25:59 +00001015 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +00001016 ThrowCompareException(OptionError,"MissingArgument",option);
1017 break;
1018 }
Cristyf9ab5152017-05-16 21:05:26 -04001019 if (LocaleCompare("trim",option+1) == 0)
1020 break;
cristy3ed852e2009-09-05 21:47:34 +00001021 if (LocaleCompare("type",option+1) == 0)
1022 {
cristybb503372010-05-27 20:51:26 +00001023 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001024 type;
1025
1026 if (*option == '+')
1027 break;
1028 i++;
cristybb503372010-05-27 20:51:26 +00001029 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +00001030 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +00001031 type=ParseCommandOption(MagickTypeOptions,MagickFalse,argv[i]);
cristy3ed852e2009-09-05 21:47:34 +00001032 if (type < 0)
1033 ThrowCompareException(OptionError,"UnrecognizedImageType",
1034 argv[i]);
1035 break;
1036 }
1037 ThrowCompareException(OptionError,"UnrecognizedOption",option)
1038 }
1039 case 'v':
1040 {
1041 if (LocaleCompare("verbose",option+1) == 0)
1042 break;
1043 if ((LocaleCompare("version",option+1) == 0) ||
1044 (LocaleCompare("-version",option+1) == 0))
1045 {
cristy4f7a6132012-12-23 00:35:19 +00001046 ListMagickVersion(stdout);
cristy3ed852e2009-09-05 21:47:34 +00001047 break;
1048 }
1049 if (LocaleCompare("virtual-pixel",option+1) == 0)
1050 {
cristybb503372010-05-27 20:51:26 +00001051 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001052 method;
1053
1054 if (*option == '+')
1055 break;
1056 i++;
cristye81f5522014-05-07 01:25:59 +00001057 if (i == (ssize_t) argc)
cristy3ed852e2009-09-05 21:47:34 +00001058 ThrowCompareException(OptionError,"MissingArgument",option);
cristy042ee782011-04-22 18:48:30 +00001059 method=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +00001060 argv[i]);
1061 if (method < 0)
1062 ThrowCompareException(OptionError,
1063 "UnrecognizedVirtualPixelMethod",argv[i]);
1064 break;
1065 }
1066 ThrowCompareException(OptionError,"UnrecognizedOption",option)
1067 }
Cristy55d3c442016-12-02 19:46:34 -05001068 case 'w':
1069 {
1070 if (LocaleCompare("write-mask",option+1) == 0)
1071 {
1072 if (*option == '+')
1073 break;
1074 i++;
1075 if (i == (ssize_t) argc)
1076 ThrowCompareException(OptionError,"MissingArgument",option);
1077 break;
1078 }
1079 ThrowCompareException(OptionError,"UnrecognizedOption",option)
1080 }
cristy3ed852e2009-09-05 21:47:34 +00001081 case '?':
1082 break;
1083 default:
1084 ThrowCompareException(OptionError,"UnrecognizedOption",option)
1085 }
cristy042ee782011-04-22 18:48:30 +00001086 fire=(GetCommandOptionFlags(MagickCommandOptions,MagickFalse,option) &
1087 FireOptionFlag) == 0 ? MagickFalse : MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00001088 if (fire != MagickFalse)
1089 FireImageStack(MagickTrue,MagickTrue,MagickTrue);
1090 }
1091 if (k != 0)
1092 ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]);
cristybb503372010-05-27 20:51:26 +00001093 if (i-- != (ssize_t) (argc-1))
cristy3ed852e2009-09-05 21:47:34 +00001094 ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
1095 if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
1096 ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
1097 FinalizeImageSettings(image_info,image,MagickTrue);
cristy94f20072009-09-12 02:12:36 +00001098 if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
1099 ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
cristy3ed852e2009-09-05 21:47:34 +00001100 image=GetImageFromList(image,0);
1101 reconstruct_image=GetImageFromList(image,1);
cristyab0cc712013-11-03 22:18:45 +00001102 offset.x=0;
1103 offset.y=0;
cristy83330932010-08-14 20:48:24 +00001104 if (subimage_search != MagickFalse)
1105 {
cristy62e52182013-03-15 14:26:17 +00001106 similarity_image=SimilarityImage(image,reconstruct_image,metric,
1107 similarity_threshold,&offset,&similarity_metric,exception);
cristy83330932010-08-14 20:48:24 +00001108 if (similarity_metric > dissimilarity_threshold)
1109 ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename);
1110 }
cristy966f1f02014-02-02 16:27:24 +00001111 if ((reconstruct_image->columns == image->columns) &&
1112 (reconstruct_image->rows == image->rows))
cristy8a9106f2011-07-05 14:39:26 +00001113 difference_image=CompareImages(image,reconstruct_image,metric,&distortion,
1114 exception);
cristy3ed852e2009-09-05 21:47:34 +00001115 else
cristy4fdfe682014-01-21 19:26:29 +00001116 if (similarity_image == (Image *) NULL)
cristy7431bb22014-02-02 18:40:36 +00001117 {
1118 if (metric == PerceptualHashErrorMetric)
cristy7e2f1aa2014-02-02 21:23:27 +00001119 difference_image=CompareImages(image,reconstruct_image,metric,
1120 &distortion,exception);
cristy7431bb22014-02-02 18:40:36 +00001121 else
1122 ThrowCompareException(OptionError,"ImageWidthsOrHeightsDiffer",
1123 image->filename);
1124 }
cristyfdad9052010-08-15 20:15:35 +00001125 else
cristy83330932010-08-14 20:48:24 +00001126 {
1127 Image
1128 *composite_image;
cristy3ed852e2009-09-05 21:47:34 +00001129
cristy83330932010-08-14 20:48:24 +00001130 /*
1131 Determine if reconstructed image is a subimage of the image.
1132 */
1133 composite_image=CloneImage(image,0,0,MagickTrue,exception);
1134 if (composite_image == (Image *) NULL)
cristy8a9106f2011-07-05 14:39:26 +00001135 difference_image=CompareImages(image,reconstruct_image,metric,
1136 &distortion,exception);
cristy83330932010-08-14 20:48:24 +00001137 else
1138 {
cristy95f8ae32013-06-17 12:26:57 +00001139 Image
1140 *distort_image;
1141
1142 RectangleInfo
1143 page;
1144
cristyfeb3e962012-03-29 17:25:55 +00001145 (void) CompositeImage(composite_image,reconstruct_image,
cristy39172402012-03-30 13:04:39 +00001146 CopyCompositeOp,MagickTrue,offset.x,offset.y,exception);
cristy8a9106f2011-07-05 14:39:26 +00001147 difference_image=CompareImages(image,composite_image,metric,
1148 &distortion,exception);
cristy83330932010-08-14 20:48:24 +00001149 if (difference_image != (Image *) NULL)
1150 {
1151 difference_image->page.x=offset.x;
1152 difference_image->page.y=offset.y;
1153 }
1154 composite_image=DestroyImage(composite_image);
cristy95f8ae32013-06-17 12:26:57 +00001155 page.width=reconstruct_image->columns;
1156 page.height=reconstruct_image->rows;
1157 page.x=offset.x;
1158 page.y=offset.y;
1159 distort_image=CropImage(image,&page,exception);
1160 if (distort_image != (Image *) NULL)
1161 {
1162 Image
1163 *sans_image;
1164
1165 sans_image=CompareImages(distort_image,reconstruct_image,metric,
1166 &distortion,exception);
1167 distort_image=DestroyImage(distort_image);
1168 if (sans_image != (Image *) NULL)
1169 sans_image=DestroyImage(sans_image);
1170 }
cristy83330932010-08-14 20:48:24 +00001171 }
1172 if (difference_image != (Image *) NULL)
1173 {
1174 AppendImageToList(&difference_image,similarity_image);
1175 similarity_image=(Image *) NULL;
1176 }
1177 }
cristy3ed852e2009-09-05 21:47:34 +00001178 if (difference_image == (Image *) NULL)
1179 status=0;
1180 else
1181 {
1182 if (image_info->verbose != MagickFalse)
Cristyf2479812015-12-12 12:17:43 -05001183 (void) SetImageColorMetric(image,reconstruct_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001184 if (*difference_image->magick == '\0')
1185 (void) CopyMagickString(difference_image->magick,image->magick,
cristy151b66d2015-04-15 10:50:31 +00001186 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001187 if (image_info->verbose == MagickFalse)
1188 {
1189 switch (metric)
1190 {
cristy343eee92010-12-11 02:17:57 +00001191 case FuzzErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001192 case MeanAbsoluteErrorMetric:
1193 case MeanSquaredErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001194 case PeakAbsoluteErrorMetric:
cristybc0adce2014-01-08 23:15:49 +00001195 case RootMeanSquaredErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001196 {
cristyb51dff52011-05-19 16:55:47 +00001197 (void) FormatLocaleFile(stderr,"%g (%g)",QuantumRange*distortion,
cristy8cd5b312010-01-07 01:10:24 +00001198 (double) distortion);
cristy3ed852e2009-09-05 21:47:34 +00001199 break;
1200 }
1201 case AbsoluteErrorMetric:
cristy4c929a72010-11-24 18:54:42 +00001202 case NormalizedCrossCorrelationErrorMetric:
cristy03d6f862014-01-08 18:34:48 +00001203 case PeakSignalToNoiseRatioErrorMetric:
cristy966f1f02014-02-02 16:27:24 +00001204 case PerceptualHashErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001205 {
cristyb51dff52011-05-19 16:55:47 +00001206 (void) FormatLocaleFile(stderr,"%g",distortion);
cristy3ed852e2009-09-05 21:47:34 +00001207 break;
1208 }
cristy03fa69f2014-01-08 18:36:49 +00001209 case MeanErrorPerPixelErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001210 {
cristyb51dff52011-05-19 16:55:47 +00001211 (void) FormatLocaleFile(stderr,"%g (%g, %g)",distortion,
cristy3ed852e2009-09-05 21:47:34 +00001212 image->error.normalized_mean_error,
1213 image->error.normalized_maximum_error);
cristy3ed852e2009-09-05 21:47:34 +00001214 break;
1215 }
cristy2cb55d52013-07-10 22:20:51 +00001216 case UndefinedErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001217 break;
1218 }
cristya5f84e02014-02-03 10:30:53 +00001219 if (subimage_search != MagickFalse)
cristy7431bb22014-02-02 18:40:36 +00001220 (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
1221 difference_image->page.x,(double) difference_image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001222 }
1223 else
1224 {
1225 double
1226 *channel_distortion;
1227
cristy8a9106f2011-07-05 14:39:26 +00001228 channel_distortion=GetImageDistortions(image,reconstruct_image,
cristyc82a27b2011-10-21 01:07:16 +00001229 metric,exception);
cristyb51dff52011-05-19 16:55:47 +00001230 (void) FormatLocaleFile(stderr,"Image: %s\n",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00001231 if ((reconstruct_image->columns != image->columns) ||
1232 (reconstruct_image->rows != image->rows))
cristyb51dff52011-05-19 16:55:47 +00001233 (void) FormatLocaleFile(stderr,"Offset: %.20g,%.20g\n",(double)
cristye8c25f92010-06-03 00:53:06 +00001234 difference_image->page.x,(double) difference_image->page.y);
cristyb51dff52011-05-19 16:55:47 +00001235 (void) FormatLocaleFile(stderr," Channel distortion: %s\n",
cristy042ee782011-04-22 18:48:30 +00001236 CommandOptionToMnemonic(MagickMetricOptions,(ssize_t) metric));
cristy3ed852e2009-09-05 21:47:34 +00001237 switch (metric)
1238 {
cristy343eee92010-12-11 02:17:57 +00001239 case FuzzErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001240 case MeanAbsoluteErrorMetric:
1241 case MeanSquaredErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001242 case PeakAbsoluteErrorMetric:
cristybc0adce2014-01-08 23:15:49 +00001243 case RootMeanSquaredErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001244 {
1245 switch (image->colorspace)
1246 {
1247 case RGBColorspace:
1248 default:
1249 {
cristyb51dff52011-05-19 16:55:47 +00001250 (void) FormatLocaleFile(stderr," red: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001251 QuantumRange*channel_distortion[RedPixelChannel],
1252 channel_distortion[RedPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001253 (void) FormatLocaleFile(stderr," green: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001254 QuantumRange*channel_distortion[GreenPixelChannel],
1255 channel_distortion[GreenPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001256 (void) FormatLocaleFile(stderr," blue: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001257 QuantumRange*channel_distortion[BluePixelChannel],
1258 channel_distortion[BluePixelChannel]);
cristy7d6d3d82014-11-09 17:00:16 +00001259 if (image->alpha_trait != UndefinedPixelTrait)
cristyb51dff52011-05-19 16:55:47 +00001260 (void) FormatLocaleFile(stderr," alpha: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001261 QuantumRange*channel_distortion[AlphaPixelChannel],
1262 channel_distortion[AlphaPixelChannel]);
cristy3ed852e2009-09-05 21:47:34 +00001263 break;
1264 }
1265 case CMYKColorspace:
1266 {
cristyb51dff52011-05-19 16:55:47 +00001267 (void) FormatLocaleFile(stderr," cyan: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001268 QuantumRange*channel_distortion[CyanPixelChannel],
1269 channel_distortion[CyanPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001270 (void) FormatLocaleFile(stderr," magenta: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001271 QuantumRange*channel_distortion[MagentaPixelChannel],
1272 channel_distortion[MagentaPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001273 (void) FormatLocaleFile(stderr," yellow: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001274 QuantumRange*channel_distortion[YellowPixelChannel],
1275 channel_distortion[YellowPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001276 (void) FormatLocaleFile(stderr," black: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001277 QuantumRange*channel_distortion[BlackPixelChannel],
1278 channel_distortion[BlackPixelChannel]);
cristy7d6d3d82014-11-09 17:00:16 +00001279 if (image->alpha_trait != UndefinedPixelTrait)
cristyb51dff52011-05-19 16:55:47 +00001280 (void) FormatLocaleFile(stderr," alpha: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001281 QuantumRange*channel_distortion[AlphaPixelChannel],
1282 channel_distortion[AlphaPixelChannel]);
cristy3ed852e2009-09-05 21:47:34 +00001283 break;
1284 }
1285 case GRAYColorspace:
1286 {
cristyb51dff52011-05-19 16:55:47 +00001287 (void) FormatLocaleFile(stderr," gray: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001288 QuantumRange*channel_distortion[GrayPixelChannel],
1289 channel_distortion[GrayPixelChannel]);
cristy7d6d3d82014-11-09 17:00:16 +00001290 if (image->alpha_trait != UndefinedPixelTrait)
cristyb51dff52011-05-19 16:55:47 +00001291 (void) FormatLocaleFile(stderr," alpha: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001292 QuantumRange*channel_distortion[AlphaPixelChannel],
1293 channel_distortion[AlphaPixelChannel]);
cristy3ed852e2009-09-05 21:47:34 +00001294 break;
1295 }
1296 }
cristyb51dff52011-05-19 16:55:47 +00001297 (void) FormatLocaleFile(stderr," all: %g (%g)\n",
cristyd3090f92011-10-18 00:05:15 +00001298 QuantumRange*channel_distortion[MaxPixelChannels],
1299 channel_distortion[MaxPixelChannels]);
cristy3ed852e2009-09-05 21:47:34 +00001300 break;
1301 }
1302 case AbsoluteErrorMetric:
cristy4c929a72010-11-24 18:54:42 +00001303 case NormalizedCrossCorrelationErrorMetric:
cristy03d6f862014-01-08 18:34:48 +00001304 case PeakSignalToNoiseRatioErrorMetric:
cristy33caf0c2014-01-09 14:42:27 +00001305 case PerceptualHashErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001306 {
1307 switch (image->colorspace)
1308 {
1309 case RGBColorspace:
1310 default:
1311 {
cristyb51dff52011-05-19 16:55:47 +00001312 (void) FormatLocaleFile(stderr," red: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001313 channel_distortion[RedPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001314 (void) FormatLocaleFile(stderr," green: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001315 channel_distortion[GreenPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001316 (void) FormatLocaleFile(stderr," blue: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001317 channel_distortion[BluePixelChannel]);
cristy7d6d3d82014-11-09 17:00:16 +00001318 if (image->alpha_trait != UndefinedPixelTrait)
cristyb51dff52011-05-19 16:55:47 +00001319 (void) FormatLocaleFile(stderr," alpha: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001320 channel_distortion[AlphaPixelChannel]);
cristy3ed852e2009-09-05 21:47:34 +00001321 break;
1322 }
1323 case CMYKColorspace:
1324 {
cristyb51dff52011-05-19 16:55:47 +00001325 (void) FormatLocaleFile(stderr," cyan: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001326 channel_distortion[CyanPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001327 (void) FormatLocaleFile(stderr," magenta: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001328 channel_distortion[MagentaPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001329 (void) FormatLocaleFile(stderr," yellow: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001330 channel_distortion[YellowPixelChannel]);
cristyb51dff52011-05-19 16:55:47 +00001331 (void) FormatLocaleFile(stderr," black: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001332 channel_distortion[BlackPixelChannel]);
cristy7d6d3d82014-11-09 17:00:16 +00001333 if (image->alpha_trait != UndefinedPixelTrait)
cristyb51dff52011-05-19 16:55:47 +00001334 (void) FormatLocaleFile(stderr," alpha: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001335 channel_distortion[AlphaPixelChannel]);
cristy3ed852e2009-09-05 21:47:34 +00001336 break;
1337 }
1338 case GRAYColorspace:
1339 {
cristyb51dff52011-05-19 16:55:47 +00001340 (void) FormatLocaleFile(stderr," gray: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001341 channel_distortion[GrayPixelChannel]);
cristy7d6d3d82014-11-09 17:00:16 +00001342 if (image->alpha_trait != UndefinedPixelTrait)
cristyb51dff52011-05-19 16:55:47 +00001343 (void) FormatLocaleFile(stderr," alpha: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001344 channel_distortion[AlphaPixelChannel]);
cristy3ed852e2009-09-05 21:47:34 +00001345 break;
1346 }
1347 }
cristyb51dff52011-05-19 16:55:47 +00001348 (void) FormatLocaleFile(stderr," all: %g\n",
cristyd3090f92011-10-18 00:05:15 +00001349 channel_distortion[MaxPixelChannels]);
cristy3ed852e2009-09-05 21:47:34 +00001350 break;
1351 }
cristy03fa69f2014-01-08 18:36:49 +00001352 case MeanErrorPerPixelErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001353 {
cristyb51dff52011-05-19 16:55:47 +00001354 (void) FormatLocaleFile(stderr," %g (%g, %g)\n",
cristyd3090f92011-10-18 00:05:15 +00001355 channel_distortion[MaxPixelChannels],
cristy3ed852e2009-09-05 21:47:34 +00001356 image->error.normalized_mean_error,
1357 image->error.normalized_maximum_error);
1358 break;
1359 }
cristy2cb55d52013-07-10 22:20:51 +00001360 case UndefinedErrorMetric:
cristy3ed852e2009-09-05 21:47:34 +00001361 break;
1362 }
1363 channel_distortion=(double *) RelinquishMagickMemory(
1364 channel_distortion);
cristya5f84e02014-02-03 10:30:53 +00001365 if (subimage_search != MagickFalse)
cristy7431bb22014-02-02 18:40:36 +00001366 (void) FormatLocaleFile(stderr," Offset: %.20g,%.20g\n",(double)
1367 difference_image->page.x,(double) difference_image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001368 }
1369 status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
1370 if ((metadata != (char **) NULL) && (format != (char *) NULL))
1371 {
1372 char
1373 *text;
1374
cristy018f07f2011-09-04 21:15:19 +00001375 text=InterpretImageProperties(image_info,difference_image,format,
1376 exception);
cristy3ed852e2009-09-05 21:47:34 +00001377 if (text == (char *) NULL)
1378 ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
1379 GetExceptionMessage(errno));
1380 (void) ConcatenateString(&(*metadata),text);
cristy3ed852e2009-09-05 21:47:34 +00001381 text=DestroyString(text);
1382 }
1383 difference_image=DestroyImageList(difference_image);
1384 }
1385 DestroyCompare();
cristy2cb55d52013-07-10 22:20:51 +00001386 if ((metric == NormalizedCrossCorrelationErrorMetric) ||
1387 (metric == UndefinedErrorMetric))
1388 {
1389 if (fabs(distortion-1.0) > CompareEpsilon)
cristyebd71f42013-09-13 22:35:48 +00001390 (void) SetImageOption(image_info,"compare:dissimilar","true");
cristy2cb55d52013-07-10 22:20:51 +00001391 }
1392 else
1393 if (fabs(distortion) > CompareEpsilon)
cristyebd71f42013-09-13 22:35:48 +00001394 (void) SetImageOption(image_info,"compare:dissimilar","true");
cristy2cb55d52013-07-10 22:20:51 +00001395 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001396}