root/ImageMagick/trunk/wand/compare.c

Revision 464, 42.2 KB (checked in by cristy, 4 weeks 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-2009 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%  Use the compare program to mathematically and visually annotate the
37%  difference between an image and its reconstruction.
38%
39*/
40
41/*
42  Include declarations.
43*/
44#include "wand/studio.h"
45#include "wand/MagickWand.h"
46#include "wand/mogrify-private.h"
47
48/*
49%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
50%                                                                             %
51%                                                                             %
52%                                                                             %
53%   C o m p a r e I m a g e C o m m a n d                                     %
54%                                                                             %
55%                                                                             %
56%                                                                             %
57%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58%
59%  CompareImageCommand() compares two images and returns the difference between
60%  them as a distortion metric and as a new image visually annotating their
61%  differences.
62%
63%  The format of the CompareImageCommand method is:
64%
65%      MagickBooleanType CompareImageCommand(ImageInfo *image_info,int argc,
66%        char **argv,char **metadata,ExceptionInfo *exception)
67%
68%  A description of each parameter follows:
69%
70%    o image_info: the image info.
71%
72%    o argc: the number of elements in the argument vector.
73%
74%    o argv: A text array containing the command line arguments.
75%
76%    o metadata: any metadata is returned here.
77%
78%    o exception: return any errors or warnings in this structure.
79%
80*/
81
82static MagickBooleanType CompareUsage(void)
83{
84  const char
85    **p;
86
87  static const char
88    *miscellaneous[]=
89    {
90      "-debug events        display copious debugging information",
91      "-help                print program options",
92      "-list type           print a list of supported option arguments",
93      "-log format          format of debugging information",
94      (char *) NULL
95    },
96    *settings[]=
97    {
98      "-alpha option        on, activate, off, deactivate, set, opaque, copy",
99      "                     transparent, extract, background, or shape",
100      "-authenticate password",
101      "                     decipher image with this password",
102      "-channel type        apply option to select image channels",
103      "-colorspace type     alternate image colorspace",
104      "-compose operator    set image composite operator",
105      "-compress type       type of pixel compression when writing the image",
106      "-decipher filename   convert cipher pixels to plain pixels",
107      "-define format:option",
108      "                     define one or more image format options",
109      "-density geometry    horizontal and vertical density of the image",
110      "-depth value         image depth",
111      "-dissimilarity-threshold value",
112      "                     maximum RMSE for (sub)image match",
113      "-encipher filename   convert plain pixels to cipher pixels",
114      "-extract geometry    extract area from image",
115      "-format \"string\"     output formatted image characteristics",
116      "-fuzz distance       colors within this distance are considered equal",
117      "-highlight-color color",
118      "                     empasize pixel differences with this color",
119      "-identify            identify the format and characteristics of the image",
120      "-interlace type      type of image interlacing scheme",
121      "-limit type value    pixel cache resource limit",
122      "-lowlight-color color",
123      "                     de-emphasize pixel differences with this color",
124      "-metric type         measure differences between images with this metric",
125      "-monitor             monitor progress",
126      "-passphrase filename get the passphrase from this file",
127      "-profile filename    add, delete, or apply an image profile",
128      "-quality value       JPEG/MIFF/PNG compression level",
129      "-quiet               suppress all warning messages",
130      "-quantize colorspace reduce colors in this colorspace",
131      "-regard-warnings     pay attention to warning messages",
132      "-respect-parentheses settings remain in effect until parenthesis boundary",
133      "-sampling-factor geometry",
134      "                     horizontal and vertical sampling factor",
135      "-seed value          seed a new sequence of pseudo-random numbers",
136      "-set attribute value set an image attribute",
137      "-quality value       JPEG/MIFF/PNG compression level",
138      "-size geometry       width and height of image",
139      "-transparent-color color",
140      "                     transparent color",
141      "-type type           image type",
142      "-verbose             print detailed information about the image",
143      "-version             print version information",
144      "-virtual-pixel method",
145      "                     virtual pixel access method",
146      (char *) NULL
147    };
148
149  (void) printf("Version: %s\n",GetMagickVersion((unsigned long *) NULL));
150  (void) printf("Copyright: %s\n",GetMagickCopyright());
151  (void) printf("Features: %s\n\n",GetMagickFeatures());
152  (void) printf("Usage: %s [options ...] image reconstruct difference\n",
153    GetClientName());
154  (void) printf("\nImage Settings:\n");
155  for (p=settings; *p != (char *) NULL; p++)
156    (void) printf("  %s\n",*p);
157  (void) printf("\nMiscellaneous Options:\n");
158  for (p=miscellaneous; *p != (char *) NULL; p++)
159    (void) printf("  %s\n",*p);
160  (void) printf(
161    "\nBy default, the image format of `file' is determined by its magic\n");
162  (void) printf(
163    "number.  To specify a particular image format, precede the filename\n");
164  (void) printf(
165    "with an image format name and a colon (i.e. ps:image) or specify the\n");
166  (void) printf(
167    "image type as the filename suffix (i.e. image.ps).  Specify 'file' as\n");
168  (void) printf("'-' for standard input or output.\n");
169  return(MagickFalse);
170}
171
172WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
173  int argc,char **argv,char **metadata,ExceptionInfo *exception)
174{
175#define DefaultDissimilarityThreshold  0.2
176#define DestroyCompare() \
177{ \
178  if (similarity_image != (Image *) NULL) \
179    similarity_image=DestroyImageList(similarity_image); \
180  if (difference_image != (Image *) NULL) \
181    difference_image=DestroyImageList(difference_image); \
182  DestroyImageStack(); \
183  for (i=0; i < (long) argc; i++) \
184    argv[i]=DestroyString(argv[i]); \
185  argv=(char **) RelinquishMagickMemory(argv); \
186}
187#define ThrowCompareException(asperity,tag,option) \
188{ \
189  if (exception->severity < (asperity)) \
190    (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
191      "`%s'",option); \
192  DestroyCompare(); \
193  return(MagickFalse); \
194}
195#define ThrowCompareInvalidArgumentException(option,argument) \
196{ \
197  (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
198    "InvalidArgument","`%s': %s",option,argument); \
199  DestroyCompare(); \
200  return(MagickFalse); \
201}
202
203  char
204    *filename,
205    *option;
206
207  const char
208    *format;
209
210  ChannelType
211    channels;
212
213  double
214    dissimilarity_threshold,
215    distortion,
216    similarity_metric;
217
218  Image
219    *difference_image,
220    *image,
221    *reconstruct_image,
222    *similarity_image;
223
224  ImageStack
225    image_stack[MaxImageStackDepth+1];
226
227  long
228    j,
229    k;
230
231  MagickBooleanType
232    fire,
233    pend;
234
235  MagickStatusType
236    status;
237
238  MetricType
239    metric;
240
241  RectangleInfo
242    offset;
243
244  register long
245    i;
246
247  /*
248    Set defaults.
249  */
250  assert(image_info != (ImageInfo *) NULL);
251  assert(image_info->signature == MagickSignature);
252  if (image_info->debug != MagickFalse)
253    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
254  assert(exception != (ExceptionInfo *) NULL);
255  if (argc == 2)
256    {
257      option=argv[1];
258      if ((LocaleCompare("version",option+1) == 0) ||
259          (LocaleCompare("-version",option+1) == 0))
260        {
261          (void) fprintf(stdout,"Version: %s\n",
262            GetMagickVersion((unsigned long *) NULL));
263          (void) fprintf(stdout,"Copyright: %s\n",GetMagickCopyright());
264          (void) fprintf(stdout,"Features: %s\n\n",GetMagickFeatures());
265          return(MagickFalse);
266        }
267    }
268  if (argc < 3)
269    {
270      (void) CompareUsage();
271      return(MagickTrue);
272    }
273  channels=AllChannels;
274  difference_image=NewImageList();
275  similarity_image=NewImageList();
276  dissimilarity_threshold=DefaultDissimilarityThreshold;
277  distortion=0.0;
278  format=(char *) NULL;
279  j=1;
280  k=0;
281  metric=UndefinedMetric;
282  NewImageStack();
283  option=(char *) NULL;
284  pend=MagickFalse;
285  reconstruct_image=NewImageList();
286  status=MagickTrue;
287  /*
288    Compare an image.
289  */
290  ReadCommandlLine(argc,&argv);
291  status=ExpandFilenames(&argc,&argv);
292  if (status == MagickFalse)
293    ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
294      GetExceptionMessage(errno));
295  for (i=1; i < (long) (argc-1); i++)
296  {
297    option=argv[i];
298    if (LocaleCompare(option,"(") == 0)
299      {
300        FireImageStack(MagickTrue,MagickTrue,pend);
301        if (k == MaxImageStackDepth)
302          ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply",
303            option);
304        PushImageStack();
305        continue;
306      }
307    if (LocaleCompare(option,")") == 0)
308      {
309        FireImageStack(MagickTrue,MagickTrue,MagickTrue);
310        if (k == 0)
311          ThrowCompareException(OptionError,"UnableToParseExpression",option);
312        PopImageStack();
313        continue;
314      }
315    if (IsMagickOption(option) == MagickFalse)
316      {
317        Image
318          *images;
319
320        /*
321          Read input image.
322        */
323        FireImageStack(MagickFalse,MagickFalse,pend);
324        filename=argv[i];
325        if ((LocaleCompare(filename,"--") == 0) && (i < (argc-1)))
326          filename=argv[++i];
327        (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
328        images=ReadImages(image_info,exception);
329        status&=(images != (Image *) NULL) &&
330          (exception->severity < ErrorException);
331        if (images == (Image *) NULL)
332          continue;
333        AppendImageStack(images);
334        continue;
335      }
336    pend=image != (Image *) NULL ? MagickTrue : MagickFalse;
337    switch (*(option+1))
338    {
339      case 'a':
340      {
341        if (LocaleCompare("alpha",option+1) == 0)
342          {
343            long
344              type;
345
346            if (*option == '+')
347              break;
348            i++;
349            if (i == (long) argc)
350              ThrowCompareException(OptionError,"MissingArgument",option);
351            type=ParseMagickOption(MagickAlphaOptions,MagickFalse,argv[i]);
352            if (type < 0)
353              ThrowCompareException(OptionError,"UnrecognizedAlphaChannelType",
354                argv[i]);
355            break;
356          }
357        if (LocaleCompare("authenticate",option+1) == 0)
358          {
359            if (*option == '+')
360              break;
361            i++;
362            if (i == (long) argc)
363              ThrowCompareException(OptionError,"MissingArgument",option);
364            break;
365          }
366        ThrowCompareException(OptionError,"UnrecognizedOption",option);
367      }
368      case 'c':
369      {
370        if (LocaleCompare("cache",option+1) == 0)
371          {
372            if (*option == '+')
373              break;
374            i++;
375            if (i == (long) argc)
376              ThrowCompareException(OptionError,"MissingArgument",option);
377            if (IsGeometry(argv[i]) == MagickFalse)
378              ThrowCompareInvalidArgumentException(option,argv[i]);
379            break;
380          }
381        if (LocaleCompare("channel",option+1) == 0)
382          {
383            long
384              channel;
385
386            if (*option == '+')
387              break;
388            i++;
389            if (i == (long) (argc-1))
390              ThrowCompareException(OptionError,"MissingArgument",option);
391            channel=ParseChannelOption(argv[i]);
392            if (channel < 0)
393              ThrowCompareException(OptionError,"UnrecognizedChannelType",
394                argv[i]);
395            channels=(ChannelType) channel;
396            break;
397          }
398        if (LocaleCompare("colorspace",option+1) == 0)
399          {
400            long
401              colorspace;
402
403            if (*option == '+')
404              break;
405            i++;
406            if (i == (long) (argc-1))
407              ThrowCompareException(OptionError,"MissingArgument",option);
408            colorspace=ParseMagickOption(MagickColorspaceOptions,MagickFalse,
409              argv[i]);
410            if (colorspace < 0)
411              ThrowCompareException(OptionError,"UnrecognizedColorspace",
412                argv[i]);
413            break;
414          }
415        if (LocaleCompare("compose",option+1) == 0)
416          {
417            long
418              compose;
419
420            if (*option == '+')
421              break;
422            i++;
423            if (i == (long) argc)
424              ThrowCompareException(OptionError,"MissingArgument",option);
425            compose=ParseMagickOption(MagickComposeOptions,MagickFalse,
426              argv[i]);
427            if (compose < 0)
428              ThrowCompareException(OptionError,"UnrecognizedComposeOperator",
429                argv[i]);
430            break;
431          }
432        if (LocaleCompare("compress",option+1) == 0)
433          {
434            long
435              compress;
436
437            if (*option == '+')
438              break;
439            i++;
440            if (i == (long) (argc-1))
441              ThrowCompareException(OptionError,"MissingArgument",option);
442            compress=ParseMagickOption(MagickCompressOptions,MagickFalse,
443              argv[i]);
444            if (compress < 0)
445              ThrowCompareException(OptionError,"UnrecognizedImageCompression",
446                argv[i]);
447            break;
448          }
449        if (LocaleCompare("concurrent",option+1) == 0)
450          break;
451        ThrowCompareException(OptionError,"UnrecognizedOption",option)
452      }
453      case 'd':
454      {
455        if (LocaleCompare("debug",option+1) == 0)
456          {
457            LogEventType
458              event_mask;
459
460            if (*option == '+')
461              break;
462            i++;
463            if (i == (long) argc)
464              ThrowCompareException(OptionError,"MissingArgument",option);
465            event_mask=SetLogEventMask(argv[i]);
466            if (event_mask == UndefinedEvents)
467              ThrowCompareException(OptionError,"UnrecognizedEventType",
468                argv[i]);
469            break;
470          }
471        if (LocaleCompare("decipher",option+1) == 0)
472          {
473            if (*option == '+')
474              break;
475            i++;
476            if (i == (long) (argc-1))
477              ThrowCompareException(OptionError,"MissingArgument",option);
478            break;
479          }
480        if (LocaleCompare("define",option+1) == 0)
481          {
482            i++;
483            if (i == (long) argc)
484              ThrowCompareException(OptionError,"MissingArgument",option);
485            if (*option == '+')
486              {
487                const char
488                  *define;
489
490                define=GetImageOption(image_info,argv[i]);
491                if (define == (const char *) NULL)
492                  ThrowCompareException(OptionError,"NoSuchOption",argv[i]);
493                break;
494              }
495            break;
496          }
497        if (LocaleCompare("density",option+1) == 0)
498          {
499            if (*option == '+')
500              break;
501            i++;
502            if (i == (long) argc)
503              ThrowCompareException(OptionError,"MissingArgument",option);
504            if (IsGeometry(argv[i]) == MagickFalse)
505              ThrowCompareInvalidArgumentException(option,argv[i]);
506            break;
507          }
508        if (LocaleCompare("depth",option+1) == 0)
509          {
510            if (*option == '+')
511              break;
512            i++;
513            if (i == (long) argc)
514              ThrowCompareException(OptionError,"MissingArgument",option);
515            if (IsGeometry(argv[i]) == MagickFalse)
516              ThrowCompareInvalidArgumentException(option,argv[i]);
517            break;
518          }
519        if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
520          {
521            if (*option == '+')
522              break;
523            i++;
524            if (i == (long) argc)
525              ThrowCompareException(OptionError,"MissingArgument",option);
526            if (IsGeometry(argv[i]) == MagickFalse)
527              ThrowCompareInvalidArgumentException(option,argv[i]);
528            if (*option == '+')
529              dissimilarity_threshold=DefaultDissimilarityThreshold;
530            else
531              dissimilarity_threshold=atof(argv[i]);
532            break;
533          }
534        if (LocaleCompare("duration",option+1) == 0)
535          {
536            if (*option == '+')
537              break;
538            i++;
539            if (i == (long) (argc-1))
540              ThrowCompareException(OptionError,"MissingArgument",option);
541            if (IsGeometry(argv[i]) == MagickFalse)
542              ThrowCompareInvalidArgumentException(option,argv[i]);
543            break;
544          }
545        ThrowCompareException(OptionError,"UnrecognizedOption",option)
546      }
547      case 'e':
548      {
549        if (LocaleCompare("encipher",option+1) == 0)
550          {
551            if (*option == '+')
552              break;
553            i++;
554            if (i == (long) (argc-1))
555              ThrowCompareException(OptionError,"MissingArgument",option);
556            break;
557          }
558        if (LocaleCompare("extract",option+1) == 0)
559          {
560            if (*option == '+')
561              break;
562            i++;
563            if (i == (long) (argc-1))
564              ThrowCompareException(OptionError,"MissingArgument",option);
565            if (IsGeometry(argv[i]) == MagickFalse)
566              ThrowCompareInvalidArgumentException(option,argv[i]);
567            break;
568          }
569        ThrowCompareException(OptionError,"UnrecognizedOption",option)
570      }
571      case 'f':
572      {
573        if (LocaleCompare("format",option+1) == 0)
574          {
575            if (*option == '+')
576              break;
577            i++;
578            if (i == (long) argc)
579              ThrowCompareException(OptionError,"MissingArgument",option);
580            format=argv[i];
581            break;
582          }
583        if (LocaleCompare("fuzz",option+1) == 0)
584          {
585            if (*option == '+')
586              break;
587            i++;
588            if (i == (long) (argc-1))
589              ThrowCompareException(OptionError,"MissingArgument",option);
590            if (IsGeometry(argv[i]) == MagickFalse)
591              ThrowCompareInvalidArgumentException(option,argv[i]);
592            break;
593          }
594        ThrowCompareException(OptionError,"UnrecognizedOption",option)
595      }
596      case 'h':
597      {
598        if ((LocaleCompare("help",option+1) == 0) ||
599            (LocaleCompare("-help",option+1) == 0))
600          return(CompareUsage());
601        if (LocaleCompare("highlight-color",option+1) == 0)
602          {
603            if (*option == '+')
604              break;
605            i++;
606            if (i == (long) (argc-1))
607              ThrowCompareException(OptionError,"MissingArgument",option);
608            break;
609          }
610        ThrowCompareException(OptionError,"UnrecognizedOption",option)
611      }
612      case 'i':
613      {
614        if (LocaleCompare("identify",option+1) == 0)
615          break;
616        if (LocaleCompare("interlace",option+1) == 0)
617          {
618            long
619              interlace;
620
621            if (*option == '+')
622              break;
623            i++;
624            if (i == (long) argc)
625              ThrowCompareException(OptionError,"MissingArgument",option);
626            interlace=ParseMagickOption(MagickInterlaceOptions,MagickFalse,
627              argv[i]);
628            if (interlace < 0)
629              ThrowCompareException(OptionError,"UnrecognizedInterlaceType",
630                argv[i]);
631            break;
632          }
633        ThrowCompareException(OptionError,"UnrecognizedOption",option)
634      }
635      case 'l':
636      {
637        if (LocaleCompare("limit",option+1) == 0)
638          {
639            char
640              *p;
641
642            double
643              value;
644
645            long
646              resource;
647
648            if (*option == '+')
649              break;
650            i++;
651            if (i == (long) argc)
652              ThrowCompareException(OptionError,"MissingArgument",option);
653            resource=ParseMagickOption(MagickResourceOptions,MagickFalse,
654              argv[i]);
655            if (resource < 0)
656              ThrowCompareException(OptionError,"UnrecognizedResourceType",
657                argv[i]);
658            i++;
659            if (i == (long) argc)
660              ThrowCompareException(OptionError,"MissingArgument",option);
661            value=strtod(argv[i],&p);
662            if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0))
663              ThrowCompareInvalidArgumentException(option,argv[i]);
664            break;
665          }
666        if (LocaleCompare("list",option+1) == 0)
667          {
668            long
669              list;
670
671            if (*option == '+')
672              break;
673            i++;
674            if (i == (long) argc)
675              ThrowCompareException(OptionError,"MissingArgument",option);
676            list=ParseMagickOption(MagickListOptions,MagickFalse,argv[i]);
677            if (list < 0)
678              ThrowCompareException(OptionError,"UnrecognizedListType",argv[i]);
679            (void) MogrifyImageInfo(image_info,(int) (i-j+1),(const char **)
680              argv+j,exception);
681            DestroyCompare();
682            return(MagickTrue);
683          }
684        if (LocaleCompare("log",option+1) == 0)
685          {
686            if (*option == '+')
687              break;
688            i++;
689            if ((i == (long) argc) || (strchr(argv[i],'%') == (char *) NULL))
690              ThrowCompareException(OptionError,"MissingArgument",option);
691            break;
692          }
693        if (LocaleCompare("lowlight-color",option+1) == 0)
694          {
695            if (*option == '+')
696              break;
697            i++;
698            if (i == (long) (argc-1))
699              ThrowCompareException(OptionError,"MissingArgument",option);
700            break;
701          }
702        ThrowCompareException(OptionError,"UnrecognizedOption",option)
703      }
704      case 'm':
705      {
706        if (LocaleCompare("matte",option+1) == 0)
707          break;
708        if (LocaleCompare("metric",option+1) == 0)
709          {
710            long
711              type;
712
713            if (*option == '+')
714              break;
715            i++;
716            if (i == (long) argc)
717              ThrowCompareException(OptionError,"MissingArgument",option);
718            type=ParseMagickOption(MagickMetricOptions,MagickTrue,argv[i]);
719            if (type < 0)
720              ThrowCompareException(OptionError,"UnrecognizedMetricType",
721                argv[i]);
722            metric=(MetricType) type;
723            break;
724          }
725        if (LocaleCompare("monitor",option+1) == 0)
726          break;
727        ThrowCompareException(OptionError,"UnrecognizedOption",option)
728      }
729      case 'p':
730      {
731        if (LocaleCompare("passphrase",option+1) == 0)
732          {
733            if (*option == '+')
734              break;
735            i++;
736            if (i == (long) argc)
737              ThrowCompareException(OptionError,"MissingArgument",option);
738            break;
739          }
740        if (LocaleCompare("profile",option+1) == 0)
741          {
742            i++;
743            if (i == (long) (argc-1))
744              ThrowCompareException(OptionError,"MissingArgument",option);
745            break;
746          }
747        ThrowCompareException(OptionError,"UnrecognizedOption",option)
748      }
749      case 'q':
750      {
751        if (LocaleCompare("quality",option+1) == 0)
752          {
753            if (*option == '+')
754              break;
755            i++;
756            if (i == (long) (argc-1))
757              ThrowCompareException(OptionError,"MissingArgument",option);
758            if (IsGeometry(argv[i]) == MagickFalse)
759              ThrowCompareInvalidArgumentException(option,argv[i]);
760            break;
761          }
762        if (LocaleCompare("quantize",option+1) == 0)
763          {
764            long
765              colorspace;
766
767            if (*option == '+')
768              break;
769            i++;
770            if (i == (long) (argc-1))
771              ThrowCompareException(OptionError,"MissingArgument",option);
772            colorspace=ParseMagickOption(MagickColorspaceOptions,
773              MagickFalse,argv[i]);
774            if (colorspace < 0)
775              ThrowCompareException(OptionError,"UnrecognizedColorspace",
776                argv[i]);
777            break;
778          }
779        if (LocaleCompare("quiet",option+1) == 0)
780          break;
781        ThrowCompareException(OptionError,"UnrecognizedOption",option)
782      }
783      case 'r':
784      {
785        if (LocaleCompare("regard-warnings",option+1) == 0)
786          break;
787        if (LocaleNCompare("respect-parentheses",option+1,17) == 0)
788          {
789            respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse;
790            break;
791          }
792        ThrowCompareException(OptionError,"UnrecognizedOption",option)
793      }
794      case 's':
795      {
796        if (LocaleCompare("sampling-factor",option+1) == 0)
797          {
798            if (*option == '+')
799              break;
800            i++;
801            if (i == (long) argc)
802              ThrowCompareException(OptionError,"MissingArgument",option);
803            if (IsGeometry(argv[i]) == MagickFalse)
804              ThrowCompareInvalidArgumentException(option,argv[i]);
805            break;
806          }
807        if (LocaleCompare("seed",option+1) == 0)
808          {
809            if (*option == '+')
810              break;
811            i++;
812            if (i == (long) (argc-1))
813              ThrowCompareException(OptionError,"MissingArgument",option);
814            if (IsGeometry(argv[i]) == MagickFalse)
815              ThrowCompareInvalidArgumentException(option,argv[i]);
816            break;
817          }
818        if (LocaleCompare("set",option+1) == 0)
819          {
820            i++;
821            if (i == (long) argc)
822              ThrowCompareException(OptionError,"MissingArgument",option);
823            if (*option == '+')
824              break;
825            i++;
826            if (i == (long) argc)
827              ThrowCompareException(OptionError,"MissingArgument",option);
828            break;
829          }
830        if (LocaleCompare("size",option+1) == 0)
831          {
832            if (*option == '+')
833              break;
834            i++;
835            if (i == (long) argc)
836              ThrowCompareException(OptionError,"MissingArgument",option);
837            if (IsGeometry(argv[i]) == MagickFalse)
838              ThrowCompareInvalidArgumentException(option,argv[i]);
839            break;
840          }
841        ThrowCompareException(OptionError,"UnrecognizedOption",option)
842      }
843      case 't':
844      {
845        if (LocaleCompare("transparent-color",option+1) == 0)
846          {
847            if (*option == '+')
848              break;
849            i++;
850            if (i == (long) (argc-1))
851              ThrowCompareException(OptionError,"MissingArgument",option);
852            break;
853          }
854        if (LocaleCompare("type",option+1) == 0)
855          {
856            long
857              type;
858
859            if (*option == '+')
860              break;
861            i++;
862            if (i == (long) argc)
863              ThrowCompareException(OptionError,"MissingArgument",option);
864            type=ParseMagickOption(MagickTypeOptions,MagickFalse,argv[i]);
865            if (type < 0)
866              ThrowCompareException(OptionError,"UnrecognizedImageType",
867                argv[i]);
868            break;
869          }
870        ThrowCompareException(OptionError,"UnrecognizedOption",option)
871      }
872      case 'v':
873      {
874        if (LocaleCompare("verbose",option+1) == 0)
875          break;
876        if ((LocaleCompare("version",option+1) == 0) ||
877            (LocaleCompare("-version",option+1) == 0))
878          {
879            (void) fprintf(stdout,"Version: %s\n",
880              GetMagickVersion((unsigned long *) NULL));
881            (void) fprintf(stdout,"Copyright: %s\n",GetMagickCopyright());
882            (void) fprintf(stdout,"Features: %s\n\n",GetMagickFeatures());
883            break;
884          }
885        if (LocaleCompare("virtual-pixel",option+1) == 0)
886          {
887            long
888              method;
889
890            if (*option == '+')
891              break;
892            i++;
893            if (i == (long) (argc-1))
894              ThrowCompareException(OptionError,"MissingArgument",option);
895            method=ParseMagickOption(MagickVirtualPixelOptions,MagickFalse,
896              argv[i]);
897            if (method < 0)
898              ThrowCompareException(OptionError,
899                "UnrecognizedVirtualPixelMethod",argv[i]);
900            break;
901          }
902        ThrowCompareException(OptionError,"UnrecognizedOption",option)
903      }
904      case '?':
905        break;
906      default:
907        ThrowCompareException(OptionError,"UnrecognizedOption",option)
908    }
909    fire=ParseMagickOption(MagickImageListOptions,MagickFalse,option+1) < 0 ?
910      MagickFalse : MagickTrue;
911    if (fire != MagickFalse)
912      FireImageStack(MagickTrue,MagickTrue,MagickTrue);
913  }
914  if (k != 0)
915    ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]);
916  if (i-- != (long) (argc-1))
917    ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
918  if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
919    ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
920  FinalizeImageSettings(image_info,image,MagickTrue);
921  if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
922    ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
923  image=GetImageFromList(image,0);
924  reconstruct_image=GetImageFromList(image,1);
925  similarity_image=SimilarityImage(image,reconstruct_image,&offset,
926    &similarity_metric,exception);
927  if (similarity_metric > dissimilarity_threshold)
928    ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename);
929  if ((reconstruct_image->columns == image->columns) &&
930      (reconstruct_image->rows == image->rows))
931    difference_image=CompareImageChannels(image,reconstruct_image,channels,
932      metric,&distortion,exception);
933  else
934    if (similarity_image != (Image *) NULL)
935      {
936        Image
937          *composite_image;
938
939        /*
940          Determine if reconstructed image is a subimage of the image.
941        */
942        composite_image=CloneImage(image,0,0,MagickTrue,exception);
943        if (composite_image == (Image *) NULL)
944          difference_image=CompareImageChannels(image,reconstruct_image,
945            channels,metric,&distortion,exception);
946        else
947          {
948            (void) CompositeImage(composite_image,CopyCompositeOp,
949              reconstruct_image,offset.x,offset.y);
950            difference_image=CompareImageChannels(image,composite_image,
951              channels,metric,&distortion,exception);
952            if (difference_image != (Image *) NULL)
953              {
954                difference_image->page.x=offset.x;
955                difference_image->page.y=offset.y;
956              }
957            composite_image=DestroyImage(composite_image);
958          }
959        if (difference_image == (Image *) NULL)
960          similarity_image=DestroyImage(similarity_image);
961        else
962          {
963            AppendImageToList(&difference_image,similarity_image);
964            similarity_image=(Image *) NULL;
965          }
966      }
967  if (difference_image == (Image *) NULL)
968    status=0;
969  else
970    {
971      if (image_info->verbose != MagickFalse)
972        (void) IsImagesEqual(image,reconstruct_image);
973      if (*difference_image->magick == '\0')
974        (void) CopyMagickString(difference_image->magick,image->magick,
975          MaxTextExtent);
976      if (image_info->verbose == MagickFalse)
977        {
978          switch (metric)
979          {
980            case MeanAbsoluteErrorMetric:
981            case MeanSquaredErrorMetric:
982            case RootMeanSquaredErrorMetric:
983            case PeakAbsoluteErrorMetric:
984            {
985              (void) fprintf(stderr,"%g (%g)",QuantumRange*distortion,(double)
986                distortion);
987              if ((reconstruct_image->columns != image->columns) ||
988                  (reconstruct_image->rows != image->rows))
989                (void) fprintf(stderr," @ %ld,%ld",difference_image->page.x,
990                  difference_image->page.y);
991              (void) fprintf(stderr,"\n");
992              break;
993            }
994            case AbsoluteErrorMetric:
995            case PeakSignalToNoiseRatioMetric:
996            {
997              (void) fprintf(stderr,"%g",distortion);
998              if ((reconstruct_image->columns != image->columns) ||
999                  (reconstruct_image->rows != image->rows))
1000                (void) fprintf(stderr," @ %ld,%ld",difference_image->page.x,
1001                  difference_image->page.y);
1002              (void) fprintf(stderr,"\n");
1003              break;
1004            }
1005            case MeanErrorPerPixelMetric:
1006            {
1007              (void) fprintf(stderr,"%g (%g, %g)",distortion,
1008                image->error.normalized_mean_error,
1009                image->error.normalized_maximum_error);
1010              if ((reconstruct_image->columns != image->columns) ||
1011                  (reconstruct_image->rows != image->rows))
1012                (void) fprintf(stderr," @ %ld,%ld",difference_image->page.x,
1013                  difference_image->page.y);
1014              (void) fprintf(stderr,"\n");
1015              break;
1016            }
1017            case UndefinedMetric:
1018              break;
1019          }
1020        }
1021      else
1022        {
1023          double
1024            *channel_distortion;
1025
1026          channel_distortion=GetImageChannelDistortions(image,reconstruct_image,
1027            metric,&image->exception);
1028          (void) fprintf(stderr,"Image: %s\n",image->filename);
1029          if ((reconstruct_image->columns != image->columns) ||
1030              (reconstruct_image->rows != image->rows))
1031            (void) fprintf(stderr,"Offset: %ld,%ld\n",difference_image->page.x,
1032              difference_image->page.y);
1033          (void) fprintf(stderr,"  Channel distortion: %s\n",
1034            MagickOptionToMnemonic(MagickMetricOptions,(long) metric));
1035          switch (metric)
1036          {
1037            case MeanAbsoluteErrorMetric:
1038            case MeanSquaredErrorMetric:
1039            case RootMeanSquaredErrorMetric:
1040            case PeakAbsoluteErrorMetric:
1041            {
1042              switch (image->colorspace)
1043              {
1044                case RGBColorspace:
1045                default:
1046                {
1047                  (void) fprintf(stderr,"    red: %g (%g)\n",
1048                    QuantumRange*channel_distortion[RedChannel],
1049                    channel_distortion[RedChannel]);
1050                  (void) fprintf(stderr,"    green: %g (%g)\n",
1051                    QuantumRange*channel_distortion[GreenChannel],
1052                    channel_distortion[GreenChannel]);
1053                  (void) fprintf(stderr,"    blue: %g (%g)\n",
1054                    QuantumRange*channel_distortion[BlueChannel],
1055                    channel_distortion[BlueChannel]);
1056                  if (image->matte != MagickFalse)
1057                    (void) fprintf(stderr,"    alpha: %g (%g)\n",
1058                      QuantumRange*channel_distortion[OpacityChannel],
1059                      channel_distortion[OpacityChannel]);
1060                  break;
1061                }
1062                case CMYKColorspace:
1063                {
1064                  (void) fprintf(stderr,"    cyan: %g (%g)\n",
1065                    QuantumRange*channel_distortion[CyanChannel],
1066                    channel_distortion[CyanChannel]);
1067                  (void) fprintf(stderr,"    magenta: %g (%g)\n",
1068                    QuantumRange*channel_distortion[MagentaChannel],
1069                    channel_distortion[MagentaChannel]);
1070                  (void) fprintf(stderr,"    yellow: %g (%g)\n",
1071                    QuantumRange*channel_distortion[YellowChannel],
1072                    channel_distortion[YellowChannel]);
1073                  (void) fprintf(stderr,"    black: %g (%g)\n",
1074                    QuantumRange*channel_distortion[BlackChannel],
1075                    channel_distortion[BlackChannel]);
1076                  if (image->matte != MagickFalse)
1077                    (void) fprintf(stderr,"    alpha: %g (%g)\n",
1078                      QuantumRange*channel_distortion[OpacityChannel],
1079                      channel_distortion[OpacityChannel]);
1080                  break;
1081                }
1082                case GRAYColorspace:
1083                {
1084                  (void) fprintf(stderr,"    gray: %g (%g)\n",
1085                    QuantumRange*channel_distortion[GrayChannel],
1086                    channel_distortion[GrayChannel]);
1087                  if (image->matte != MagickFalse)
1088                    (void) fprintf(stderr,"    alpha: %g (%g)\n",
1089                      QuantumRange*channel_distortion[OpacityChannel],
1090                      channel_distortion[OpacityChannel]);
1091                  break;
1092                }
1093              }
1094              (void) fprintf(stderr,"    all: %g (%g)\n",
1095                QuantumRange*channel_distortion[AllChannels],
1096                channel_distortion[AllChannels]);
1097              break;
1098            }
1099            case AbsoluteErrorMetric:
1100            case PeakSignalToNoiseRatioMetric:
1101            {
1102              switch (image->colorspace)
1103              {
1104                case RGBColorspace:
1105                default:
1106                {
1107                  (void) fprintf(stderr,"    red: %g\n",
1108                    channel_distortion[RedChannel]);
1109                  (void) fprintf(stderr,"    green: %g\n",
1110                    channel_distortion[GreenChannel]);
1111                  (void) fprintf(stderr,"    blue: %g\n",
1112                    channel_distortion[BlueChannel]);
1113                  if (image->matte != MagickFalse)
1114                    (void) fprintf(stderr,"    alpha: %g\n",
1115                      channel_distortion[OpacityChannel]);
1116                  break;
1117                }
1118                case CMYKColorspace:
1119                {
1120                  (void) fprintf(stderr,"    cyan: %g\n",
1121                    channel_distortion[CyanChannel]);
1122                  (void) fprintf(stderr,"    magenta: %g\n",
1123                    channel_distortion[MagentaChannel]);
1124                  (void) fprintf(stderr,"    yellow: %g\n",
1125                    channel_distortion[YellowChannel]);
1126                  (void) fprintf(stderr,"    black: %g\n",
1127                    channel_distortion[BlackChannel]);
1128                  if (image->matte != MagickFalse)
1129                    (void) fprintf(stderr,"    alpha: %g\n",
1130                      channel_distortion[OpacityChannel]);
1131                  break;
1132                }
1133                case GRAYColorspace:
1134                {
1135                  (void) fprintf(stderr,"    gray: %g\n",
1136                    channel_distortion[GrayChannel]);
1137                  if (image->matte != MagickFalse)
1138                    (void) fprintf(stderr,"    alpha: %g\n",
1139                      channel_distortion[OpacityChannel]);
1140                  break;
1141                }
1142              }
1143              (void) fprintf(stderr,"    all: %g\n",
1144                channel_distortion[AllChannels]);
1145              break;
1146            }
1147            case MeanErrorPerPixelMetric:
1148            {
1149              (void) fprintf(stderr,"    %g (%g, %g)\n",
1150                channel_distortion[AllChannels],
1151                image->error.normalized_mean_error,
1152                image->error.normalized_maximum_error);
1153              break;
1154            }
1155            case UndefinedMetric:
1156              break;
1157          }
1158          channel_distortion=(double *) RelinquishMagickMemory(
1159            channel_distortion);
1160        }
1161      status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
1162      if ((metadata != (char **) NULL) && (format != (char *) NULL))
1163        {
1164          char
1165            *text;
1166
1167          text=InterpretImageProperties(image_info,difference_image,format);
1168          if (text == (char *) NULL)
1169            ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
1170              GetExceptionMessage(errno));
1171          (void) ConcatenateString(&(*metadata),text);
1172          (void) ConcatenateString(&(*metadata),"\n");
1173          text=DestroyString(text);
1174        }
1175      difference_image=DestroyImageList(difference_image);
1176    }
1177  DestroyCompare();
1178  return(status != 0 ? MagickTrue : MagickFalse);
1179}
Note: See TracBrowser for help on using the browser.