root / ImageMagick / trunk / wand / compare.c

Revision 11956, 36.6 kB (checked in by cristy, 10 days ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%               CCCC   OOO   M   M  PPPP    AAA   RRRR    EEEEE               %
7%              C      O   O  MM MM  P   P  A   A  R   R   E                   %
8%              C      O   O  M M M  PPPP   AAAAA  RRRR    EEE                 %
9%              C      O   O  M   M  P      A   A  R R     E                   %
10%               CCCC   OOO   M   M  P      A   A  R  R    EEEEE               %
11%                                                                             %
12%                                                                             %
13%                         Image Comparison Methods                            %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                               December 2003                                 %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "wand/studio.h"
44#include "wand/MagickWand.h"
45#include "wand/mogrify-private.h"
46
47/*
48%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49%                                                                             %
50%                                                                             %
51%                                                                             %
52%   C o m p a r e I m a g e C o m m a n d                                     %
53%                                                                             %
54%                                                                             %
55%                                                                             %
56%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57%
58%  CompareImageCommand() compares two images and returns the difference between
59%  them as a distortion metric and as a new image visually annotating their
60%  differences.
61%
62%  The format of the CompareImageCommand method is:
63%
64%      MagickBooleanType CompareImageCommand(ImageInfo *image_info,int argc,
65%        char **argv,char **metadata,ExceptionInfo *exception)
66%
67%  A description of each parameter follows:
68%
69%    o image_info: the image info.
70%
71%    o argc: the number of elements in the argument vector.
72%
73%    o argv: A text array containing the command line arguments.
74%
75%    o metadata: any metadata is returned here.
76%
77%    o exception: Return any errors or warnings in this structure.
78%
79*/
80
81static void CompareUsage(void)
82{
83  const char
84    **p;
85
86  static const char
87    *miscellaneous[]=
88    {
89      "-debug events        display copious debugging information",
90      "-help                print program options",
91      "-list type           print a list of supported option arguments",
92      "-log format          format of debugging information",
93      (char *) NULL
94    },
95    *settings[]=
96    {
97      "-alpha option        activate, deactivate, reset, or set the alpha channel",
98      "-authenticate password",
99      "                     decipher image with this password",
100      "-channel type        apply option to select image channels",
101      "-colorspace type     alternate image colorspace",
102      "-compose operator    set image composite operator",
103      "-compress type       type of pixel compression when writing the image",
104      "-decipher filename   convert cipher pixels to plain pixels",
105      "-define format:option",
106      "                     define one or more image format options",
107      "-density geometry    horizontal and vertical density of the image",
108      "-depth value         image depth",
109      "-encipher filename   convert plain pixels to cipher pixels",
110      "-extract geometry    extract area from image",
111      "-format \"string\"     output formatted image characteristics",
112      "-fuzz distance       colors within this distance are considered equal",
113      "-highlight-color color",
114      "                     empasize pixel differences with this color",
115      "-identify            identify the format and characteristics of the image",
116      "-interlace type      type of image interlacing scheme",
117      "-limit type value    pixel cache resource limit",
118      "-lowlight-color color",
119      "                     de-emphasize pixel differences with this color",
120      "-metric type         measure differences between images with this metric",
121      "-monitor             monitor progress",
122      "-passphrase filename get the passphrase from this file",
123      "-profile filename    add, delete, or apply an image profile",
124      "-quality value       JPEG/MIFF/PNG compression level",
125      "-quiet               suppress all warning messages",
126      "-quantize colorspace reduce colors in this colorspace",
127      "-regard-warnings     pay attention to warning messages",
128      "-respect-parenthesis settings remain in effect until parenthesis boundary",
129      "-sampling-factor geometry",
130      "                     horizontal and vertical sampling factor",
131      "-seed value          seed a new sequence of pseudo-random numbers",
132      "-set attribute value set an image attribute",
133      "-size geometry       width and height of image",
134      "-transparent-color color",
135      "                     transparent color",
136      "-type type           image type",
137      "-verbose             print detailed information about the image",
138      "-version             print version information",
139      "-virtual-pixel method",
140      "                     virtual pixel access method",
141      (char *) NULL
142    };
143
144  (void) printf("Version: %s\n",GetMagickVersion((unsigned long *) NULL));
145  (void) printf("Copyright: %s\n\n",GetMagickCopyright());
146  (void) printf("Usage: %s [options ...] image reconstruct difference\n",
147    GetClientName());
148  (void) printf("\nImage Settings:\n");
149  for (p=settings; *p != (char *) NULL; p++)
150    (void) printf("  %s\n",*p);
151  (void) printf("\nMiscellaneous Options:\n");
152  for (p=miscellaneous; *p != (char *) NULL; p++)
153    (void) printf("  %s\n",*p);
154  (void) printf(
155    "\nBy default, the image format of `file' is determined by its magic\n");
156  (void) printf(
157    "number.  To specify a particular image format, precede the filename\n");
158  (void) printf(
159    "with an image format name and a colon (i.e. ps:image) or specify the\n");
160  (void) printf(
161    "image type as the filename suffix (i.e. image.ps).  Specify 'file' as\n");
162  (void) printf("'-' for standard input or output.\n");
163  exit(0);
164}
165
166WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
167  int argc,char **argv,char **metadata,ExceptionInfo *exception)
168{
169#define DestroyCompare() \
170{ \
171  DestroyImageStack(); \
172  for (i=0; i < (long) argc; i++) \
173    argv[i]=DestroyString(argv[i]); \
174  argv=(char **) RelinquishMagickMemory(argv); \
175}
176#define ThrowCompareException(asperity,tag,option) \
177{ \
178  if (exception->severity < (asperity)) \
179    (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
180      "`%s'",option); \
181  DestroyCompare(); \
182  return(MagickFalse); \
183}
184#define ThrowCompareInvalidArgumentException(option,argument) \
185{ \
186  (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
187    "InvalidArgument","`%s': %s",argument,option); \
188  DestroyCompare(); \
189  return(MagickFalse); \
190}
191
192  char
193    *filename,
194    *option;
195
196  const char
197    *format;
198
199  ChannelType
200    channels;
201
202  double
203    distortion;
204
205  Image
206    *difference_image,
207    *image,
208    *reconstruct_image;
209
210  ImageStack
211    image_stack[MaxImageStackDepth+1];
212
213  long
214    j,
215    k;
216
217  MagickBooleanType
218    fire,
219    pend;
220
221  MagickStatusType
222    status;
223
224  MetricType
225    metric;
226
227  register long
228    i;
229
230  /*
231    Set defaults.
232  */
233  assert(image_info != (ImageInfo *) NULL);
234  assert(image_info->signature == MagickSignature);
235  if (image_info->debug != MagickFalse)
236    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
237  assert(exception != (ExceptionInfo *) NULL);
238  if (argc == 2)
239    {
240      option=argv[1];
241      if ((LocaleCompare("version",option+1) == 0) ||
242          (LocaleCompare("-version",option+1) == 0))
243        {
244          (void) fprintf(stdout,"Version: %s\n",
245            GetMagickVersion((unsigned long *) NULL));
246          (void) fprintf(stdout,"Copyright: %s\n\n",GetMagickCopyright());
247          return(MagickFalse);
248        }
249    }
250  if (argc < 3)
251    CompareUsage();
252  channels=AllChannels;
253  difference_image=NewImageList();
254  distortion=0.0;
255  format=(char *) NULL;
256  j=1;
257  k=0;
258  metric=UndefinedMetric;
259  NewImageStack();
260  option=(char *) NULL;
261  pend=MagickFalse;
262  reconstruct_image=NewImageList();
263  status=MagickTrue;
264  /*
265    Compare an image.
266  */
267  ReadCommandlLine(argc,&argv);
268  status=ExpandFilenames(&argc,&argv);
269  if (status == MagickFalse)
270    ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
271      strerror(errno));
272  for (i=1; i < (long) (argc-1); i++)
273  {
274    option=argv[i];
275    if (LocaleCompare(option,"(") == 0)
276      {
277        FireImageStack(MagickTrue,MagickTrue,pend);
278        if (k == MaxImageStackDepth)
279          ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply",
280            option);
281        PushImageStack();
282        continue;
283      }
284    if (LocaleCompare(option,")") == 0)
285      {
286        FireImageStack(MagickTrue,MagickTrue,MagickTrue);
287        if (k == 0)
288          ThrowCompareException(OptionError,"UnableToParseExpression",option);
289        PopImageStack();
290        continue;
291      }
292    if (IsMagickOption(option) == MagickFalse)
293      {
294        Image
295          *images;
296
297        /*
298          Read input image.
299        */
300        FireImageStack(MagickTrue,MagickTrue,pend);
301        filename=argv[i];
302        if ((LocaleCompare(filename,"--") == 0) && (i < (argc-1)))
303          filename=argv[++i];
304        (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
305        images=ReadImage(image_info,exception);
306        status&=(images != (Image *) NULL) &&
307          (exception->severity < ErrorException);
308        if (images == (Image *) NULL)
309          continue;
310        AppendImageStack(images);
311        continue;
312      }
313    pend=image != (Image *) NULL ? MagickTrue : MagickFalse;
314    switch (*(option+1))
315    {
316      case 'a':
317      {
318        if (LocaleCompare("alpha",option+1) == 0)
319          {
320            long
321              type;
322
323            if (*option == '+')
324              break;
325            i++;
326            if (i == (long) argc)
327              ThrowCompareException(OptionError,"MissingArgument",option);
328            type=ParseMagickOption(MagickAlphaOptions,MagickFalse,argv[i]);
329            if (type < 0)
330              ThrowCompareException(OptionError,"UnrecognizedAlphaChannelType",
331                argv[i]);
332            break;
333          }
334        if (LocaleCompare("authenticate",option+1) == 0)
335          {
336            if (*option == '+')
337              break;
338            i++;
339            if (i == (long) argc)
340              ThrowCompareException(OptionError,"MissingArgument",option);
341            break;
342          }
343        ThrowCompareException(OptionError,"UnrecognizedOption",option);
344      }
345      case 'c':
346      {
347        if (LocaleCompare("cache",option+1) == 0)
348          {
349            if (*option == '+')
350              break;
351            i++;
352            if (i == (long) argc)
353              ThrowCompareException(OptionError,"MissingArgument",option);
354            if (IsGeometry(argv[i]) == MagickFalse)
355              ThrowCompareInvalidArgumentException(option,argv[i]);
356            break;
357          }
358        if (LocaleCompare("channel",option+1) == 0)
359          {
360            long
361              channel;
362
363            if (*option == '+')
364              break;
365            i++;
366            if (i == (long) (argc-1))
367              ThrowCompareException(OptionError,"MissingArgument",option);
368            channel=ParseChannelOption(argv[i]);
369            if (channel < 0)
370              ThrowCompareException(OptionError,"UnrecognizedChannelType",
371                argv[i]);
372            channels=(ChannelType) channel;
373            break;
374          }
375        if (LocaleCompare("colorspace",option+1) == 0)
376          {
377            long
378              colorspace;
379
380            if (*option == '+')
381              break;
382            i++;
383            if (i == (long) (argc-1))
384              ThrowCompareException(OptionError,"MissingArgument",option);
385            colorspace=ParseMagickOption(MagickColorspaceOptions,MagickFalse,
386              argv[i]);
387            if (colorspace < 0)
388              ThrowCompareException(OptionError,"UnrecognizedColorspace",
389                argv[i]);
390            break;
391          }
392        if (LocaleCompare("compose",option+1) == 0)
393          {
394            long
395              compose;
396
397            if (*option == '+')
398              break;
399            i++;
400            if (i == (long) argc)
401              ThrowCompareException(OptionError,"MissingArgument",option);
402            compose=ParseMagickOption(MagickComposeOptions,MagickFalse,
403              argv[i]);
404            if (compose < 0)
405              ThrowCompareException(OptionError,"UnrecognizedComposeOperator",
406                argv[i]);
407            break;
408          }
409        if (LocaleCompare("compress",option+1) == 0)
410          {
411            long
412              compress;
413
414            if (*option == '+')
415              break;
416            i++;
417            if (i == (long) (argc-1))
418              ThrowCompareException(OptionError,"MissingArgument",option);
419            compress=ParseMagickOption(MagickCompressOptions,MagickFalse,
420              argv[i]);
421            if (compress < 0)
422              ThrowCompareException(OptionError,"UnrecognizedImageCompression",
423                argv[i]);
424            break;
425          }
426        ThrowCompareException(OptionError,"UnrecognizedOption",option)
427      }
428      case 'd':
429      {
430        if (LocaleCompare("debug",option+1) == 0)
431          {
432            LogEventType
433              event_mask;
434
435            if (*option == '+')
436              break;
437            i++;
438            if (i == (long) argc)
439              ThrowCompareException(OptionError,"MissingArgument",option);
440            event_mask=SetLogEventMask(argv[i]);
441            if (event_mask == UndefinedEvents)
442              ThrowCompareException(OptionError,"UnrecognizedEventType",
443                argv[i]);
444            break;
445          }
446        if (LocaleCompare("decipher",option+1) == 0)
447          {
448            if (*option == '+')
449              break;
450            i++;
451            if (i == (long) (argc-1))
452              ThrowCompareException(OptionError,"MissingArgument",option);
453            break;
454          }
455        if (LocaleCompare("define",option+1) == 0)
456          {
457            i++;
458            if (i == (long) argc)
459              ThrowCompareException(OptionError,"MissingArgument",option);
460            if (*option == '+')
461              {
462                const char
463                  *define;
464
465                define=GetImageOption(image_info,argv[i]);
466                if (define == (const char *) NULL)
467                  ThrowCompareException(OptionError,"NoSuchOption",argv[i]);
468                break;
469              }
470            break;
471          }
472        if (LocaleCompare("density",option+1) == 0)
473          {
474            if (*option == '+')
475              break;
476            i++;
477            if (i == (long) argc)
478              ThrowCompareException(OptionError,"MissingArgument",option);
479            if (IsGeometry(argv[i]) == MagickFalse)
480              ThrowCompareInvalidArgumentException(option,argv[i]);
481            break;
482          }
483        if (LocaleCompare("depth",option+1) == 0)
484          {
485            if (*option == '+')
486              break;
487            i++;
488            if (i == (long) argc)
489              ThrowCompareException(OptionError,"MissingArgument",option);
490            if (IsGeometry(argv[i]) == MagickFalse)
491              ThrowCompareInvalidArgumentException(option,argv[i]);
492            break;
493          }
494        ThrowCompareException(OptionError,"UnrecognizedOption",option)
495      }
496      case 'e':
497      {
498        if (LocaleCompare("encipher",option+1) == 0)
499          {
500            if (*option == '+')
501              break;
502            i++;
503            if (i == (long) (argc-1))
504              ThrowCompareException(OptionError,"MissingArgument",option);
505            break;
506          }
507        if (LocaleCompare("extract",option+1) == 0)
508          {
509            if (*option == '+')
510              break;
511            i++;
512            if (i == (long) (argc-1))
513              ThrowCompareException(OptionError,"MissingArgument",option);
514            if (IsGeometry(argv[i]) == MagickFalse)
515              ThrowCompareInvalidArgumentException(option,argv[i]);
516            break;
517          }
518        ThrowCompareException(OptionError,"UnrecognizedOption",option)
519      }
520      case 'f':
521      {
522        if (LocaleCompare("format",option+1) == 0)
523          {
524            if (*option == '+')
525              break;
526            i++;
527            if (i == (long) argc)
528              ThrowCompareException(OptionError,"MissingArgument",option);
529            format=argv[i];
530            break;
531          }
532        if (LocaleCompare("fuzz",option+1) == 0)
533          {
534            if (*option == '+')
535              break;
536            i++;
537            if (i == (long) (argc-1))
538              ThrowCompareException(OptionError,"MissingArgument",option);
539            if (IsGeometry(argv[i]) == MagickFalse)
540              ThrowCompareInvalidArgumentException(option,argv[i]);
541            break;
542          }
543        ThrowCompareException(OptionError,"UnrecognizedOption",option)
544      }
545      case 'h':
546      {
547        if ((LocaleCompare("help",option+1) == 0) ||
548            (LocaleCompare("-help",option+1) == 0))
549          CompareUsage();
550        if (LocaleCompare("highlight-color",option+1) == 0)
551          {
552            if (*option == '+')
553              break;
554            i++;
555            if (i == (long) (argc-1))
556              ThrowCompareException(OptionError,"MissingArgument",option);
557            break;
558          }
559        ThrowCompareException(OptionError,"UnrecognizedOption",option)
560      }
561      case 'i':
562      {
563        if (LocaleCompare("identify",option+1) == 0)
564          break;
565        if (LocaleCompare("interlace",option+1) == 0)
566          {
567            long
568              interlace;
569
570            if (*option == '+')
571              break;
572            i++;
573            if (i == (long) argc)
574              ThrowCompareException(OptionError,"MissingArgument",option);
575            interlace=ParseMagickOption(MagickInterlaceOptions,MagickFalse,
576              argv[i]);
577            if (interlace < 0)
578              ThrowCompareException(OptionError,"UnrecognizedInterlaceType",
579                argv[i]);
580            break;
581          }
582        ThrowCompareException(OptionError,"UnrecognizedOption",option)
583      }
584      case 'l':
585      {
586        if (LocaleCompare("limit",option+1) == 0)
587          {
588            char
589              *p;
590
591            long
592              resource;
593
594            if (*option == '+')
595              break;
596            i++;
597            if (i == (long) argc)
598              ThrowCompareException(OptionError,"MissingArgument",option);
599            resource=ParseMagickOption(MagickResourceOptions,MagickFalse,
600              argv[i]);
601            if (resource < 0)
602              ThrowCompareException(OptionError,"UnrecognizedResourceType",
603                argv[i]);
604            i++;
605            if (i == (long) argc)
606              ThrowCompareException(OptionError,"MissingArgument",option);
607            (void) strtod(argv[i],&p);
608            if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0))
609              ThrowCompareInvalidArgumentException(option,argv[i]);
610            break;
611          }
612        if (LocaleCompare("log",option+1) == 0)
613          {
614            if (*option == '+')
615              break;
616            i++;
617            if ((i == (long) argc) || (strchr(argv[i],'%') == (char *) NULL))
618              ThrowCompareException(OptionError,"MissingArgument",option);
619            break;
620          }
621        if (LocaleCompare("lowlight-color",option+1) == 0)
622          {
623            if (*option == '+')
624              break;
625            i++;
626            if (i == (long) (argc-1))
627              ThrowCompareException(OptionError,"MissingArgument",option);
628            break;
629          }
630        ThrowCompareException(OptionError,"UnrecognizedOption",option)
631      }
632      case 'm':
633      {
634        if (LocaleCompare("matte",option+1) == 0)
635          break;
636        if (LocaleCompare("metric",option+1) == 0)
637          {
638            long
639              type;
640
641            if (*option == '+')
642              break;
643            i++;
644            if (i == (long) argc)
645              ThrowCompareException(OptionError,"MissingArgument",option);
646            type=ParseMagickOption(MagickMetricOptions,MagickTrue,argv[i]);
647            if (type < 0)
648              ThrowCompareException(OptionError,"UnrecognizedMetricType",
649                argv[i]);
650            metric=(MetricType) type;
651            break;
652          }
653        if (LocaleCompare("monitor",option+1) == 0)
654          break;
655        ThrowCompareException(OptionError,"UnrecognizedOption",option)
656      }
657      case 'p':
658      {
659        if (LocaleCompare("passphrase",option+1) == 0)
660          {
661            if (*option == '+')
662              break;
663            i++;
664            if (i == (long) argc)
665              ThrowCompareException(OptionError,"MissingArgument",option);
666            break;
667          }
668        if (LocaleCompare("profile",option+1) == 0)
669          {
670            i++;
671            if (i == (long) (argc-1))
672              ThrowCompareException(OptionError,"MissingArgument",option);
673            break;
674          }
675        ThrowCompareException(OptionError,"UnrecognizedOption",option)
676      }
677      case 'q':
678      {
679        if (LocaleCompare("quality",option+1) == 0)
680          {
681            if (*option == '+')
682              break;
683            i++;
684            if (i == (long) (argc-1))
685              ThrowCompareException(OptionError,"MissingArgument",option);
686            if (IsGeometry(argv[i]) == MagickFalse)
687              ThrowCompareInvalidArgumentException(option,argv[i]);
688            break;
689          }
690        if (LocaleCompare("quantize",option+1) == 0)
691          {
692            long
693              colorspace;
694
695            if (*option == '+')
696              break;
697            i++;
698            if (i == (long) (argc-1))
699              ThrowCompareException(OptionError,"MissingArgument",option);
700            colorspace=ParseMagickOption(MagickColorspaceOptions,
701              MagickFalse,argv[i]);
702            if (colorspace < 0)
703              ThrowCompareException(OptionError,"UnrecognizedColorspace",
704                argv[i]);
705            break;
706          }
707        if (LocaleCompare("quiet",option+1) == 0)
708          break;
709        ThrowCompareException(OptionError,"UnrecognizedOption",option)
710      }
711      case 'r':
712      {
713        if (LocaleCompare("regard-warnings",option+1) == 0)
714          break;
715        if (LocaleCompare("respect-parenthesis",option+1) == 0)
716          {
717            respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse;
718            break;
719          }
720        ThrowCompareException(OptionError,"UnrecognizedOption",option)
721      }
722      case 's':
723      {
724        if (LocaleCompare("sampling-factor",option+1) == 0)
725          {
726            if (*option == '+')
727              break;
728            i++;
729            if (i == (long) argc)
730              ThrowCompareException(OptionError,"MissingArgument",option);
731            if (IsGeometry(argv[i]) == MagickFalse)
732              ThrowCompareInvalidArgumentException(option,argv[i]);
733            break;
734          }
735        if (LocaleCompare("seed",option+1) == 0)
736          {
737            if (*option == '+')
738              break;
739            i++;
740            if (i == (long) (argc-1))
741              ThrowCompareException(OptionError,"MissingArgument",option);
742            if (IsGeometry(argv[i]) == MagickFalse)
743              ThrowCompareInvalidArgumentException(option,argv[i]);
744            break;
745          }
746        if (LocaleCompare("set",option+1) == 0)
747          {
748            i++;
749            if (i == (long) argc)
750              ThrowCompareException(OptionError,"MissingArgument",option);
751            if (*option == '+')
752              break;
753            i++;
754            if (i == (long) argc)
755              ThrowCompareException(OptionError,"MissingArgument",option);
756            break;
757          }
758        if (LocaleCompare("size",option+1) == 0)
759          {
760            if (*option == '+')
761              break;
762            i++;
763            if (i == (long) argc)
764              ThrowCompareException(OptionError,"MissingArgument",option);
765            if (IsGeometry(argv[i]) == MagickFalse)
766              ThrowCompareInvalidArgumentException(option,argv[i]);
767            break;
768          }
769        ThrowCompareException(OptionError,"UnrecognizedOption",option)
770      }
771      case 't':
772      {
773        if (LocaleCompare("transparent-color",option+1) == 0)
774          {
775            if (*option == '+')
776              break;
777            i++;
778            if (i == (long) (argc-1))
779              ThrowCompareException(OptionError,"MissingArgument",option);
780            break;
781          }
782        if (LocaleCompare("type",option+1) == 0)
783          {
784            long
785              type;
786
787            if (*option == '+')
788              break;
789            i++;
790            if (i == (long) argc)
791              ThrowCompareException(OptionError,"MissingArgument",option);
792            type=ParseMagickOption(MagickTypeOptions,MagickFalse,argv[i]);
793            if (type < 0)
794              ThrowCompareException(OptionError,"UnrecognizedImageType",
795                argv[i]);
796            break;
797          }
798        ThrowCompareException(OptionError,"UnrecognizedOption",option)
799      }
800      case 'v':
801      {
802        if (LocaleCompare("verbose",option+1) == 0)
803          break;
804        if ((LocaleCompare("version",option+1) == 0) ||
805            (LocaleCompare("-version",option+1) == 0))
806          {
807            (void) fprintf(stdout,"Version: %s\n",
808              GetMagickVersion((unsigned long *) NULL));
809            (void) fprintf(stdout,"Copyright: %s\n\n",GetMagickCopyright());
810            break;
811          }
812        if (LocaleCompare("virtual-pixel",option+1) == 0)
813          {
814            long
815              method;
816
817            if (*option == '+')
818              break;
819            i++;
820            if (i == (long) (argc-1))
821              ThrowCompareException(OptionError,"MissingArgument",option);
822            method=ParseMagickOption(MagickVirtualPixelOptions,MagickFalse,
823              argv[i]);
824            if (method < 0)
825              ThrowCompareException(OptionError,
826                "UnrecognizedVirtualPixelMethod",argv[i]);
827            break;
828          }
829        ThrowCompareException(OptionError,"UnrecognizedOption",option)
830      }
831      case '?':
832        break;
833      default:
834        ThrowCompareException(OptionError,"UnrecognizedOption",option)
835    }
836    fire=ParseMagickOption(MagickMogrifyOptions,MagickFalse,option+1) < 0 ?
837      MagickFalse : MagickTrue;
838    if (fire != MagickFalse)
839      FireImageStack(MagickTrue,MagickTrue,MagickTrue);
840  }
841  if (k != 0)
842    ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]);
843  if (i-- != (long) (argc-1))
844    ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
845  if ((image == (Image *) NULL) ||
846      (GetImageListLength(image) < 2))
847    ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
848  FireImageStack(MagickTrue,MagickTrue,MagickTrue);
849  image=GetImageFromList(image,0);
850  reconstruct_image=GetImageFromList(image,1);
851  difference_image=CompareImageChannels(image,reconstruct_image,channels,
852    metric,&distortion,exception);
853  if (difference_image == (Image *) NULL)
854    status=0;
855  else
856    {
857      if (image_info->verbose != MagickFalse)
858        (void) IsImagesEqual(image,reconstruct_image);
859      status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
860      if ((metadata != (char **) NULL) && (format != (char *) NULL))
861        {
862          char
863            *text;
864
865          text=InterpretImageProperties(image_info,difference_image,format);
866          if (text == (char *) NULL)
867            ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
868              strerror(errno));
869          (void) ConcatenateString(&(*metadata),text);
870          (void) ConcatenateString(&(*metadata),"\n");
871          text=DestroyString(text);
872        }
873      difference_image=DestroyImageList(difference_image);
874      if (image_info->verbose == MagickFalse)
875        switch (metric)
876        {
877          case MeanAbsoluteErrorMetric:
878          case MeanSquaredErrorMetric:
879          case RootMeanSquaredErrorMetric:
880          case PeakAbsoluteErrorMetric:
881          {
882            (void) fprintf(stderr,"%g (%g)\n",distortion,(double) (QuantumScale*
883              distortion));
884            break;
885          }
886          case AbsoluteErrorMetric:
887          case PeakSignalToNoiseRatioMetric:
888          {
889            (void) fprintf(stderr,"%g\n",distortion);
890            break;
891          }
892          case MeanErrorPerPixelMetric:
893          {
894            (void) fprintf(stderr,"%g (%g, %g)\n",distortion,
895              image->error.normalized_mean_error,
896              image->error.normalized_maximum_error);
897            break;
898          }
899          case UndefinedMetric:
900            break;
901        }
902      else
903        {
904          double
905            *channel_distortion;
906
907 
908          channel_distortion=GetImageChannelDistortions(image,reconstruct_image,
909            metric,&image->exception);
910          (void) fprintf(stderr,"Image: %s\n",image->filename);
911          (void) fprintf(stderr,"  Channel distortion: %s\n",
912            MagickOptionToMnemonic(MagickMetricOptions,(long) metric));
913          switch (metric)
914          {
915            case MeanAbsoluteErrorMetric:
916            case MeanSquaredErrorMetric:
917            case RootMeanSquaredErrorMetric:
918            case PeakAbsoluteErrorMetric:
919            {
920              switch (image->colorspace)
921              {
922                case RGBColorspace:
923                default:
924                {
925                  (void) fprintf(stderr,"    red: %g (%g)\n",
926                    channel_distortion[RedChannel],(double) QuantumScale*
927                    channel_distortion[RedChannel]);
928                  (void) fprintf(stderr,"    green: %g (%g)\n",
929                    channel_distortion[GreenChannel],(double) QuantumScale*
930                    channel_distortion[GreenChannel]);
931                  (void) fprintf(stderr,"    blue: %g (%g)\n",
932                    channel_distortion[BlueChannel],(double) QuantumScale*
933                    channel_distortion[BlueChannel]);
934                  if (image->matte != MagickFalse)
935                    (void) fprintf(stderr,"    alpha: %g (%g)\n",
936                      channel_distortion[OpacityChannel],(double) QuantumScale*
937                      channel_distortion[OpacityChannel]);
938                  break;
939                }
940                case CMYKColorspace:
941                {
942                  (void) fprintf(stderr,"    cyan: %g (%g)\n",
943                    channel_distortion[CyanChannel],(double) QuantumScale*
944                    channel_distortion[CyanChannel]);
945                  (void) fprintf(stderr,"    magenta: %g (%g)\n",
946                    channel_distortion[MagentaChannel],(double) QuantumScale*
947                    channel_distortion[MagentaChannel]);
948                  (void) fprintf(stderr,"    yellow: %g (%g)\n",
949                    channel_distortion[YellowChannel],(double) QuantumScale*
950                    channel_distortion[YellowChannel]);