MagickWand  6.7.5
compare.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %               CCCC   OOO   M   M  PPPP    AAA   RRRR    EEEEE               %
00007 %              C      O   O  MM MM  P   P  A   A  R   R   E                   %
00008 %              C      O   O  M M M  PPPP   AAAAA  RRRR    EEE                 %
00009 %              C      O   O  M   M  P      A   A  R R     E                   %
00010 %               CCCC   OOO   M   M  P      A   A  R  R    EEEEE               %
00011 %                                                                             %
00012 %                                                                             %
00013 %                         Image Comparison Methods                            %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                               December 2003                                 %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %  Use the compare program to mathematically and visually annotate the
00037 %  difference between an image and its reconstruction.
00038 %
00039 */
00040 
00041 /*
00042   Include declarations.
00043 */
00044 #include "MagickWand/studio.h"
00045 #include "MagickWand/MagickWand.h"
00046 #include "MagickWand/mogrify-private.h"
00047 #include "MagickCore/string-private.h"
00048 
00049 /*
00050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00051 %                                                                             %
00052 %                                                                             %
00053 %                                                                             %
00054 %   C o m p a r e I m a g e C o m m a n d                                     %
00055 %                                                                             %
00056 %                                                                             %
00057 %                                                                             %
00058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00059 %
00060 %  CompareImagesCommand() compares two images and returns the difference between
00061 %  them as a distortion metric and as a new image visually annotating their
00062 %  differences.
00063 %
00064 %  The format of the CompareImagesCommand method is:
00065 %
00066 %      MagickBooleanType CompareImagesCommand(ImageInfo *image_info,int argc,
00067 %        char **argv,char **metadata,ExceptionInfo *exception)
00068 %
00069 %  A description of each parameter follows:
00070 %
00071 %    o image_info: the image info.
00072 %
00073 %    o argc: the number of elements in the argument vector.
00074 %
00075 %    o argv: A text array containing the command line arguments.
00076 %
00077 %    o metadata: any metadata is returned here.
00078 %
00079 %    o exception: return any errors or warnings in this structure.
00080 %
00081 */
00082 
00083 static MagickBooleanType CompareUsage(void)
00084 {
00085   const char
00086     **p;
00087 
00088   static const char
00089     *miscellaneous[]=
00090     {
00091       "-debug events        display copious debugging information",
00092       "-help                print program options",
00093       "-list type           print a list of supported option arguments",
00094       "-log format          format of debugging information",
00095       (char *) NULL
00096     },
00097     *settings[]=
00098     {
00099       "-alpha option        on, activate, off, deactivate, set, opaque, copy",
00100       "                     transparent, extract, background, or shape",
00101       "-authenticate password",
00102       "                     decipher image with this password",
00103       "-channel type        apply option to select image channels",
00104       "-colorspace type     alternate image colorspace",
00105       "-compose operator    set image composite operator",
00106       "-compress type       type of pixel compression when writing the image",
00107       "-decipher filename   convert cipher pixels to plain pixels",
00108       "-define format:option",
00109       "                     define one or more image format options",
00110       "-density geometry    horizontal and vertical density of the image",
00111       "-depth value         image depth",
00112       "-dissimilarity-threshold value",
00113       "                     maximum distortion for (sub)image match",
00114       "-encipher filename   convert plain pixels to cipher pixels",
00115       "-extract geometry    extract area from image",
00116       "-format \"string\"     output formatted image characteristics",
00117       "-fuzz distance       colors within this distance are considered equal",
00118       "-highlight-color color",
00119       "                     empasize pixel differences with this color",
00120       "-identify            identify the format and characteristics of the image",
00121       "-interlace type      type of image interlacing scheme",
00122       "-limit type value    pixel cache resource limit",
00123       "-lowlight-color color",
00124       "                     de-emphasize pixel differences with this color",
00125       "-metric type         measure differences between images with this metric",
00126       "-monitor             monitor progress",
00127       "-passphrase filename get the passphrase from this file",
00128       "-profile filename    add, delete, or apply an image profile",
00129       "-quality value       JPEG/MIFF/PNG compression level",
00130       "-quiet               suppress all warning messages",
00131       "-quantize colorspace reduce colors in this colorspace",
00132       "-regard-warnings     pay attention to warning messages",
00133       "-respect-parentheses settings remain in effect until parenthesis boundary",
00134       "-sampling-factor geometry",
00135       "                     horizontal and vertical sampling factor",
00136       "-seed value          seed a new sequence of pseudo-random numbers",
00137       "-set attribute value set an image attribute",
00138       "-quality value       JPEG/MIFF/PNG compression level",
00139       "-size geometry       width and height of image",
00140       "-subimage-search     search for subimage",
00141       "-transparent-color color",
00142       "                     transparent color",
00143       "-type type           image type",
00144       "-verbose             print detailed information about the image",
00145       "-version             print version information",
00146       "-virtual-pixel method",
00147       "                     virtual pixel access method",
00148       (char *) NULL
00149     };
00150 
00151   (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
00152   (void) printf("Copyright: %s\n",GetMagickCopyright());
00153   (void) printf("Features: %s\n\n",GetMagickFeatures());
00154   (void) printf("Usage: %s [options ...] image reconstruct difference\n",
00155     GetClientName());
00156   (void) printf("\nImage Settings:\n");
00157   for (p=settings; *p != (char *) NULL; p++)
00158     (void) printf("  %s\n",*p);
00159   (void) printf("\nMiscellaneous Options:\n");
00160   for (p=miscellaneous; *p != (char *) NULL; p++)
00161     (void) printf("  %s\n",*p);
00162   (void) printf(
00163     "\nBy default, the image format of `file' is determined by its magic\n");
00164   (void) printf(
00165     "number.  To specify a particular image format, precede the filename\n");
00166   (void) printf(
00167     "with an image format name and a colon (i.e. ps:image) or specify the\n");
00168   (void) printf(
00169     "image type as the filename suffix (i.e. image.ps).  Specify 'file' as\n");
00170   (void) printf("'-' for standard input or output.\n");
00171   return(MagickFalse);
00172 }
00173 
00174 WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info,
00175   int argc,char **argv,char **metadata,ExceptionInfo *exception)
00176 {
00177 #define DefaultDissimilarityThreshold  0.31830988618379067154
00178 #define DestroyCompare() \
00179 { \
00180   if (similarity_image != (Image *) NULL) \
00181     similarity_image=DestroyImageList(similarity_image); \
00182   if (difference_image != (Image *) NULL) \
00183     difference_image=DestroyImageList(difference_image); \
00184   DestroyImageStack(); \
00185   for (i=0; i < (ssize_t) argc; i++) \
00186     argv[i]=DestroyString(argv[i]); \
00187   argv=(char **) RelinquishMagickMemory(argv); \
00188 }
00189 #define ThrowCompareException(asperity,tag,option) \
00190 { \
00191   if (exception->severity < (asperity)) \
00192     (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
00193       "`%s'",option); \
00194   DestroyCompare(); \
00195   return(MagickFalse); \
00196 }
00197 #define ThrowCompareInvalidArgumentException(option,argument) \
00198 { \
00199   (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
00200     "InvalidArgument","`%s': %s",option,argument); \
00201   DestroyCompare(); \
00202   return(MagickFalse); \
00203 }
00204 
00205   char
00206     *filename,
00207     *option;
00208 
00209   const char
00210     *format;
00211 
00212   double
00213     dissimilarity_threshold,
00214     distortion,
00215     similarity_metric;
00216 
00217   Image
00218     *difference_image,
00219     *image,
00220     *reconstruct_image,
00221     *similarity_image;
00222 
00223   ImageStack
00224     image_stack[MaxImageStackDepth+1];
00225 
00226   MagickBooleanType
00227     fire,
00228     pend,
00229     respect_parenthesis,
00230     subimage_search;
00231 
00232   MagickStatusType
00233     status;
00234 
00235   MetricType
00236     metric;
00237 
00238   RectangleInfo
00239     offset;
00240 
00241   register ssize_t
00242     i;
00243 
00244   ssize_t
00245     j,
00246     k;
00247 
00248   /*
00249     Set defaults.
00250   */
00251   assert(image_info != (ImageInfo *) NULL);
00252   assert(image_info->signature == MagickSignature);
00253   if (image_info->debug != MagickFalse)
00254     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00255   assert(exception != (ExceptionInfo *) NULL);
00256   if (argc == 2)
00257     {
00258       option=argv[1];
00259       if ((LocaleCompare("version",option+1) == 0) ||
00260           (LocaleCompare("-version",option+1) == 0))
00261         {
00262           (void) FormatLocaleFile(stdout,"Version: %s\n",
00263             GetMagickVersion((size_t *) NULL));
00264           (void) FormatLocaleFile(stdout,"Copyright: %s\n",
00265             GetMagickCopyright());
00266           (void) FormatLocaleFile(stdout,"Features: %s\n\n",
00267             GetMagickFeatures());
00268           return(MagickFalse);
00269         }
00270     }
00271   if (argc < 3)
00272     return(CompareUsage());
00273   difference_image=NewImageList();
00274   similarity_image=NewImageList();
00275   dissimilarity_threshold=DefaultDissimilarityThreshold;
00276   distortion=0.0;
00277   format=(char *) NULL;
00278   j=1;
00279   k=0;
00280   metric=UndefinedMetric;
00281   NewImageStack();
00282   option=(char *) NULL;
00283   pend=MagickFalse;
00284   reconstruct_image=NewImageList();
00285   respect_parenthesis=MagickFalse;
00286   status=MagickTrue;
00287   subimage_search=MagickFalse;
00288   /*
00289     Compare an image.
00290   */
00291   ReadCommandlLine(argc,&argv);
00292   status=ExpandFilenames(&argc,&argv);
00293   if (status == MagickFalse)
00294     ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
00295       GetExceptionMessage(errno));
00296   for (i=1; i < (ssize_t) (argc-1); i++)
00297   {
00298     option=argv[i];
00299     if (LocaleCompare(option,"(") == 0)
00300       {
00301         FireImageStack(MagickTrue,MagickTrue,pend);
00302         if (k == MaxImageStackDepth)
00303           ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply",
00304             option);
00305         PushImageStack();
00306         continue;
00307       }
00308     if (LocaleCompare(option,")") == 0)
00309       {
00310         FireImageStack(MagickTrue,MagickTrue,MagickTrue);
00311         if (k == 0)
00312           ThrowCompareException(OptionError,"UnableToParseExpression",option);
00313         PopImageStack();
00314         continue;
00315       }
00316     if (IsCommandOption(option) == MagickFalse)
00317       {
00318         Image
00319           *images;
00320 
00321         /*
00322           Read input image.
00323         */
00324         FireImageStack(MagickFalse,MagickFalse,pend);
00325         filename=argv[i];
00326         if ((LocaleCompare(filename,"--") == 0) && (i < (ssize_t) (argc-1)))
00327           filename=argv[++i];
00328         (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
00329         images=ReadImages(image_info,exception);
00330         status&=(images != (Image *) NULL) &&
00331           (exception->severity < ErrorException);
00332         if (images == (Image *) NULL)
00333           continue;
00334         AppendImageStack(images);
00335         continue;
00336       }
00337     pend=image != (Image *) NULL ? MagickTrue : MagickFalse;
00338     switch (*(option+1))
00339     {
00340       case 'a':
00341       {
00342         if (LocaleCompare("alpha",option+1) == 0)
00343           {
00344             ssize_t
00345               type;
00346 
00347             if (*option == '+')
00348               break;
00349             i++;
00350             if (i == (ssize_t) argc)
00351               ThrowCompareException(OptionError,"MissingArgument",option);
00352             type=ParseCommandOption(MagickAlphaOptions,MagickFalse,argv[i]);
00353             if (type < 0)
00354               ThrowCompareException(OptionError,"UnrecognizedAlphaChannelType",
00355                 argv[i]);
00356             break;
00357           }
00358         if (LocaleCompare("authenticate",option+1) == 0)
00359           {
00360             if (*option == '+')
00361               break;
00362             i++;
00363             if (i == (ssize_t) argc)
00364               ThrowCompareException(OptionError,"MissingArgument",option);
00365             break;
00366           }
00367         ThrowCompareException(OptionError,"UnrecognizedOption",option);
00368       }
00369       case 'c':
00370       {
00371         if (LocaleCompare("cache",option+1) == 0)
00372           {
00373             if (*option == '+')
00374               break;
00375             i++;
00376             if (i == (ssize_t) argc)
00377               ThrowCompareException(OptionError,"MissingArgument",option);
00378             if (IsGeometry(argv[i]) == MagickFalse)
00379               ThrowCompareInvalidArgumentException(option,argv[i]);
00380             break;
00381           }
00382         if (LocaleCompare("channel",option+1) == 0)
00383           {
00384             ssize_t
00385               channel;
00386 
00387             if (*option == '+')
00388               break;
00389             i++;
00390             if (i == (ssize_t) (argc-1))
00391               ThrowCompareException(OptionError,"MissingArgument",option);
00392             channel=ParseChannelOption(argv[i]);
00393             if (channel < 0)
00394               ThrowCompareException(OptionError,"UnrecognizedChannelType",
00395                 argv[i]);
00396             SetPixelChannelMapMask(image,(ChannelType) channel);
00397             break;
00398           }
00399         if (LocaleCompare("colorspace",option+1) == 0)
00400           {
00401             ssize_t
00402               colorspace;
00403 
00404             if (*option == '+')
00405               break;
00406             i++;
00407             if (i == (ssize_t) (argc-1))
00408               ThrowCompareException(OptionError,"MissingArgument",option);
00409             colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,
00410               argv[i]);
00411             if (colorspace < 0)
00412               ThrowCompareException(OptionError,"UnrecognizedColorspace",
00413                 argv[i]);
00414             break;
00415           }
00416         if (LocaleCompare("compose",option+1) == 0)
00417           {
00418             ssize_t
00419               compose;
00420 
00421             if (*option == '+')
00422               break;
00423             i++;
00424             if (i == (ssize_t) argc)
00425               ThrowCompareException(OptionError,"MissingArgument",option);
00426             compose=ParseCommandOption(MagickComposeOptions,MagickFalse,
00427               argv[i]);
00428             if (compose < 0)
00429               ThrowCompareException(OptionError,"UnrecognizedComposeOperator",
00430                 argv[i]);
00431             break;
00432           }
00433         if (LocaleCompare("compress",option+1) == 0)
00434           {
00435             ssize_t
00436               compress;
00437 
00438             if (*option == '+')
00439               break;
00440             i++;
00441             if (i == (ssize_t) (argc-1))
00442               ThrowCompareException(OptionError,"MissingArgument",option);
00443             compress=ParseCommandOption(MagickCompressOptions,MagickFalse,
00444               argv[i]);
00445             if (compress < 0)
00446               ThrowCompareException(OptionError,"UnrecognizedImageCompression",
00447                 argv[i]);
00448             break;
00449           }
00450         if (LocaleCompare("concurrent",option+1) == 0)
00451           break;
00452         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00453       }
00454       case 'd':
00455       {
00456         if (LocaleCompare("debug",option+1) == 0)
00457           {
00458             LogEventType
00459               event_mask;
00460 
00461             if (*option == '+')
00462               break;
00463             i++;
00464             if (i == (ssize_t) argc)
00465               ThrowCompareException(OptionError,"MissingArgument",option);
00466             event_mask=SetLogEventMask(argv[i]);
00467             if (event_mask == UndefinedEvents)
00468               ThrowCompareException(OptionError,"UnrecognizedEventType",
00469                 argv[i]);
00470             break;
00471           }
00472         if (LocaleCompare("decipher",option+1) == 0)
00473           {
00474             if (*option == '+')
00475               break;
00476             i++;
00477             if (i == (ssize_t) (argc-1))
00478               ThrowCompareException(OptionError,"MissingArgument",option);
00479             break;
00480           }
00481         if (LocaleCompare("define",option+1) == 0)
00482           {
00483             i++;
00484             if (i == (ssize_t) argc)
00485               ThrowCompareException(OptionError,"MissingArgument",option);
00486             if (*option == '+')
00487               {
00488                 const char
00489                   *define;
00490 
00491                 define=GetImageOption(image_info,argv[i]);
00492                 if (define == (const char *) NULL)
00493                   ThrowCompareException(OptionError,"NoSuchOption",argv[i]);
00494                 break;
00495               }
00496             break;
00497           }
00498         if (LocaleCompare("density",option+1) == 0)
00499           {
00500             if (*option == '+')
00501               break;
00502             i++;
00503             if (i == (ssize_t) argc)
00504               ThrowCompareException(OptionError,"MissingArgument",option);
00505             if (IsGeometry(argv[i]) == MagickFalse)
00506               ThrowCompareInvalidArgumentException(option,argv[i]);
00507             break;
00508           }
00509         if (LocaleCompare("depth",option+1) == 0)
00510           {
00511             if (*option == '+')
00512               break;
00513             i++;
00514             if (i == (ssize_t) argc)
00515               ThrowCompareException(OptionError,"MissingArgument",option);
00516             if (IsGeometry(argv[i]) == MagickFalse)
00517               ThrowCompareInvalidArgumentException(option,argv[i]);
00518             break;
00519           }
00520         if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
00521           {
00522             if (*option == '+')
00523               break;
00524             i++;
00525             if (i == (ssize_t) argc)
00526               ThrowCompareException(OptionError,"MissingArgument",option);
00527             if (IsGeometry(argv[i]) == MagickFalse)
00528               ThrowCompareInvalidArgumentException(option,argv[i]);
00529             if (*option == '+')
00530               dissimilarity_threshold=DefaultDissimilarityThreshold;
00531             else
00532               dissimilarity_threshold=StringToDouble(argv[i],(char **) NULL);
00533             break;
00534           }
00535         if (LocaleCompare("duration",option+1) == 0)
00536           {
00537             if (*option == '+')
00538               break;
00539             i++;
00540             if (i == (ssize_t) (argc-1))
00541               ThrowCompareException(OptionError,"MissingArgument",option);
00542             if (IsGeometry(argv[i]) == MagickFalse)
00543               ThrowCompareInvalidArgumentException(option,argv[i]);
00544             break;
00545           }
00546         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00547       }
00548       case 'e':
00549       {
00550         if (LocaleCompare("encipher",option+1) == 0)
00551           {
00552             if (*option == '+')
00553               break;
00554             i++;
00555             if (i == (ssize_t) (argc-1))
00556               ThrowCompareException(OptionError,"MissingArgument",option);
00557             break;
00558           }
00559         if (LocaleCompare("extract",option+1) == 0)
00560           {
00561             if (*option == '+')
00562               break;
00563             i++;
00564             if (i == (ssize_t) (argc-1))
00565               ThrowCompareException(OptionError,"MissingArgument",option);
00566             if (IsGeometry(argv[i]) == MagickFalse)
00567               ThrowCompareInvalidArgumentException(option,argv[i]);
00568             break;
00569           }
00570         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00571       }
00572       case 'f':
00573       {
00574         if (LocaleCompare("format",option+1) == 0)
00575           {
00576             if (*option == '+')
00577               break;
00578             i++;
00579             if (i == (ssize_t) argc)
00580               ThrowCompareException(OptionError,"MissingArgument",option);
00581             format=argv[i];
00582             break;
00583           }
00584         if (LocaleCompare("fuzz",option+1) == 0)
00585           {
00586             if (*option == '+')
00587               break;
00588             i++;
00589             if (i == (ssize_t) (argc-1))
00590               ThrowCompareException(OptionError,"MissingArgument",option);
00591             if (IsGeometry(argv[i]) == MagickFalse)
00592               ThrowCompareInvalidArgumentException(option,argv[i]);
00593             break;
00594           }
00595         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00596       }
00597       case 'h':
00598       {
00599         if ((LocaleCompare("help",option+1) == 0) ||
00600             (LocaleCompare("-help",option+1) == 0))
00601           return(CompareUsage());
00602         if (LocaleCompare("highlight-color",option+1) == 0)
00603           {
00604             if (*option == '+')
00605               break;
00606             i++;
00607             if (i == (ssize_t) (argc-1))
00608               ThrowCompareException(OptionError,"MissingArgument",option);
00609             break;
00610           }
00611         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00612       }
00613       case 'i':
00614       {
00615         if (LocaleCompare("identify",option+1) == 0)
00616           break;
00617         if (LocaleCompare("interlace",option+1) == 0)
00618           {
00619             ssize_t
00620               interlace;
00621 
00622             if (*option == '+')
00623               break;
00624             i++;
00625             if (i == (ssize_t) argc)
00626               ThrowCompareException(OptionError,"MissingArgument",option);
00627             interlace=ParseCommandOption(MagickInterlaceOptions,MagickFalse,
00628               argv[i]);
00629             if (interlace < 0)
00630               ThrowCompareException(OptionError,"UnrecognizedInterlaceType",
00631                 argv[i]);
00632             break;
00633           }
00634         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00635       }
00636       case 'l':
00637       {
00638         if (LocaleCompare("limit",option+1) == 0)
00639           {
00640             char
00641               *p;
00642 
00643             double
00644               value;
00645 
00646             ssize_t
00647               resource;
00648 
00649             if (*option == '+')
00650               break;
00651             i++;
00652             if (i == (ssize_t) argc)
00653               ThrowCompareException(OptionError,"MissingArgument",option);
00654             resource=ParseCommandOption(MagickResourceOptions,MagickFalse,
00655               argv[i]);
00656             if (resource < 0)
00657               ThrowCompareException(OptionError,"UnrecognizedResourceType",
00658                 argv[i]);
00659             i++;
00660             if (i == (ssize_t) argc)
00661               ThrowCompareException(OptionError,"MissingArgument",option);
00662             value=StringToDouble(argv[i],&p);
00663             (void) value;
00664             if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0))
00665               ThrowCompareInvalidArgumentException(option,argv[i]);
00666             break;
00667           }
00668         if (LocaleCompare("list",option+1) == 0)
00669           {
00670             ssize_t
00671               list;
00672 
00673             if (*option == '+')
00674               break;
00675             i++;
00676             if (i == (ssize_t) argc)
00677               ThrowCompareException(OptionError,"MissingArgument",option);
00678             list=ParseCommandOption(MagickListOptions,MagickFalse,argv[i]);
00679             if (list < 0)
00680               ThrowCompareException(OptionError,"UnrecognizedListType",argv[i]);
00681             status=MogrifyImageInfo(image_info,(int) (i-j+1),(const char **)
00682               argv+j,exception);
00683             DestroyCompare();
00684             return(status != 0 ? MagickFalse : MagickTrue);
00685           }
00686         if (LocaleCompare("log",option+1) == 0)
00687           {
00688             if (*option == '+')
00689               break;
00690             i++;
00691             if ((i == (ssize_t) argc) || (strchr(argv[i],'%') == (char *) NULL))
00692               ThrowCompareException(OptionError,"MissingArgument",option);
00693             break;
00694           }
00695         if (LocaleCompare("lowlight-color",option+1) == 0)
00696           {
00697             if (*option == '+')
00698               break;
00699             i++;
00700             if (i == (ssize_t) (argc-1))
00701               ThrowCompareException(OptionError,"MissingArgument",option);
00702             break;
00703           }
00704         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00705       }
00706       case 'm':
00707       {
00708         if (LocaleCompare("matte",option+1) == 0)
00709           break;
00710         if (LocaleCompare("metric",option+1) == 0)
00711           {
00712             ssize_t
00713               type;
00714 
00715             if (*option == '+')
00716               break;
00717             i++;
00718             if (i == (ssize_t) argc)
00719               ThrowCompareException(OptionError,"MissingArgument",option);
00720             type=ParseCommandOption(MagickMetricOptions,MagickTrue,argv[i]);
00721             if (type < 0)
00722               ThrowCompareException(OptionError,"UnrecognizedMetricType",
00723                 argv[i]);
00724             metric=(MetricType) type;
00725             break;
00726           }
00727         if (LocaleCompare("monitor",option+1) == 0)
00728           break;
00729         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00730       }
00731       case 'p':
00732       {
00733         if (LocaleCompare("passphrase",option+1) == 0)
00734           {
00735             if (*option == '+')
00736               break;
00737             i++;
00738             if (i == (ssize_t) argc)
00739               ThrowCompareException(OptionError,"MissingArgument",option);
00740             break;
00741           }
00742         if (LocaleCompare("profile",option+1) == 0)
00743           {
00744             i++;
00745             if (i == (ssize_t) (argc-1))
00746               ThrowCompareException(OptionError,"MissingArgument",option);
00747             break;
00748           }
00749         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00750       }
00751       case 'q':
00752       {
00753         if (LocaleCompare("quality",option+1) == 0)
00754           {
00755             if (*option == '+')
00756               break;
00757             i++;
00758             if (i == (ssize_t) (argc-1))
00759               ThrowCompareException(OptionError,"MissingArgument",option);
00760             if (IsGeometry(argv[i]) == MagickFalse)
00761               ThrowCompareInvalidArgumentException(option,argv[i]);
00762             break;
00763           }
00764         if (LocaleCompare("quantize",option+1) == 0)
00765           {
00766             ssize_t
00767               colorspace;
00768 
00769             if (*option == '+')
00770               break;
00771             i++;
00772             if (i == (ssize_t) (argc-1))
00773               ThrowCompareException(OptionError,"MissingArgument",option);
00774             colorspace=ParseCommandOption(MagickColorspaceOptions,
00775               MagickFalse,argv[i]);
00776             if (colorspace < 0)
00777               ThrowCompareException(OptionError,"UnrecognizedColorspace",
00778                 argv[i]);
00779             break;
00780           }
00781         if (LocaleCompare("quiet",option+1) == 0)
00782           break;
00783         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00784       }
00785       case 'r':
00786       {
00787         if (LocaleCompare("regard-warnings",option+1) == 0)
00788           break;
00789         if (LocaleNCompare("respect-parentheses",option+1,17) == 0)
00790           {
00791             respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse;
00792             break;
00793           }
00794         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00795       }
00796       case 's':
00797       {
00798         if (LocaleCompare("sampling-factor",option+1) == 0)
00799           {
00800             if (*option == '+')
00801               break;
00802             i++;
00803             if (i == (ssize_t) argc)
00804               ThrowCompareException(OptionError,"MissingArgument",option);
00805             if (IsGeometry(argv[i]) == MagickFalse)
00806               ThrowCompareInvalidArgumentException(option,argv[i]);
00807             break;
00808           }
00809         if (LocaleCompare("seed",option+1) == 0)
00810           {
00811             if (*option == '+')
00812               break;
00813             i++;
00814             if (i == (ssize_t) (argc-1))
00815               ThrowCompareException(OptionError,"MissingArgument",option);
00816             if (IsGeometry(argv[i]) == MagickFalse)
00817               ThrowCompareInvalidArgumentException(option,argv[i]);
00818             break;
00819           }
00820         if (LocaleCompare("set",option+1) == 0)
00821           {
00822             i++;
00823             if (i == (ssize_t) argc)
00824               ThrowCompareException(OptionError,"MissingArgument",option);
00825             if (*option == '+')
00826               break;
00827             i++;
00828             if (i == (ssize_t) argc)
00829               ThrowCompareException(OptionError,"MissingArgument",option);
00830             break;
00831           }
00832         if (LocaleCompare("size",option+1) == 0)
00833           {
00834             if (*option == '+')
00835               break;
00836             i++;
00837             if (i == (ssize_t) argc)
00838               ThrowCompareException(OptionError,"MissingArgument",option);
00839             if (IsGeometry(argv[i]) == MagickFalse)
00840               ThrowCompareInvalidArgumentException(option,argv[i]);
00841             break;
00842           }
00843         if (LocaleCompare("subimage-search",option+1) == 0)
00844           {
00845             if (*option == '+')
00846               {
00847                 subimage_search=MagickFalse;
00848                 break;
00849               }
00850             subimage_search=MagickTrue;
00851             break;
00852           }
00853         if (LocaleCompare("synchronize",option+1) == 0)
00854           break;
00855         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00856       }
00857       case 't':
00858       {
00859         if (LocaleCompare("taint",option+1) == 0)
00860           break;
00861         if (LocaleCompare("transparent-color",option+1) == 0)
00862           {
00863             if (*option == '+')
00864               break;
00865             i++;
00866             if (i == (ssize_t) (argc-1))
00867               ThrowCompareException(OptionError,"MissingArgument",option);
00868             break;
00869           }
00870         if (LocaleCompare("type",option+1) == 0)
00871           {
00872             ssize_t
00873               type;
00874 
00875             if (*option == '+')
00876               break;
00877             i++;
00878             if (i == (ssize_t) argc)
00879               ThrowCompareException(OptionError,"MissingArgument",option);
00880             type=ParseCommandOption(MagickTypeOptions,MagickFalse,argv[i]);
00881             if (type < 0)
00882               ThrowCompareException(OptionError,"UnrecognizedImageType",
00883                 argv[i]);
00884             break;
00885           }
00886         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00887       }
00888       case 'v':
00889       {
00890         if (LocaleCompare("verbose",option+1) == 0)
00891           break;
00892         if ((LocaleCompare("version",option+1) == 0) ||
00893             (LocaleCompare("-version",option+1) == 0))
00894           {
00895             (void) FormatLocaleFile(stdout,"Version: %s\n",
00896               GetMagickVersion((size_t *) NULL));
00897             (void) FormatLocaleFile(stdout,"Copyright: %s\n",
00898               GetMagickCopyright());
00899             (void) FormatLocaleFile(stdout,"Features: %s\n\n",
00900               GetMagickFeatures());
00901             break;
00902           }
00903         if (LocaleCompare("virtual-pixel",option+1) == 0)
00904           {
00905             ssize_t
00906               method;
00907 
00908             if (*option == '+')
00909               break;
00910             i++;
00911             if (i == (ssize_t) (argc-1))
00912               ThrowCompareException(OptionError,"MissingArgument",option);
00913             method=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
00914               argv[i]);
00915             if (method < 0)
00916               ThrowCompareException(OptionError,
00917                 "UnrecognizedVirtualPixelMethod",argv[i]);
00918             break;
00919           }
00920         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00921       }
00922       case '?':
00923         break;
00924       default:
00925         ThrowCompareException(OptionError,"UnrecognizedOption",option)
00926     }
00927     fire=(GetCommandOptionFlags(MagickCommandOptions,MagickFalse,option) &
00928       FireOptionFlag) == 0 ?  MagickFalse : MagickTrue;
00929     if (fire != MagickFalse)
00930       FireImageStack(MagickTrue,MagickTrue,MagickTrue);
00931   }
00932   if (k != 0)
00933     ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]);
00934   if (i-- != (ssize_t) (argc-1))
00935     ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
00936   if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
00937     ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
00938   FinalizeImageSettings(image_info,image,MagickTrue);
00939   if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
00940     ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
00941   image=GetImageFromList(image,0);
00942   reconstruct_image=GetImageFromList(image,1);
00943   if (subimage_search != MagickFalse)
00944     {
00945       similarity_image=SimilarityImage(image,reconstruct_image,metric,&offset,
00946         &similarity_metric,exception);
00947       if (similarity_metric > dissimilarity_threshold)
00948         ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename);
00949     }
00950   if ((reconstruct_image->columns == image->columns) &&
00951       (reconstruct_image->rows == image->rows))
00952     difference_image=CompareImages(image,reconstruct_image,metric,&distortion,
00953       exception);
00954   else
00955     if (similarity_image == (Image *) NULL)
00956       ThrowCompareException(OptionError,"ImageWidthsOrHeightsDiffer",
00957         image->filename)
00958     else
00959       {
00960         Image
00961           *composite_image;
00962 
00963         /*
00964           Determine if reconstructed image is a subimage of the image.
00965         */
00966         composite_image=CloneImage(image,0,0,MagickTrue,exception);
00967         if (composite_image == (Image *) NULL)
00968           difference_image=CompareImages(image,reconstruct_image,metric,
00969             &distortion,exception);
00970         else
00971           {
00972             (void) CompositeImage(composite_image,CopyCompositeOp,
00973               reconstruct_image,offset.x,offset.y,exception);
00974             difference_image=CompareImages(image,composite_image,metric,
00975               &distortion,exception);
00976             if (difference_image != (Image *) NULL)
00977               {
00978                 difference_image->page.x=offset.x;
00979                 difference_image->page.y=offset.y;
00980               }
00981             composite_image=DestroyImage(composite_image);
00982           }
00983         if (difference_image != (Image *) NULL)
00984           {
00985             AppendImageToList(&difference_image,similarity_image);
00986             similarity_image=(Image *) NULL;
00987           }
00988       }
00989   if (difference_image == (Image *) NULL)
00990     status=0;
00991   else
00992     {
00993       if (image_info->verbose != MagickFalse)
00994         (void) IsImagesEqual(image,reconstruct_image,exception);
00995       if (*difference_image->magick == '\0')
00996         (void) CopyMagickString(difference_image->magick,image->magick,
00997           MaxTextExtent);
00998       if (image_info->verbose == MagickFalse)
00999         {
01000           switch (metric)
01001           {
01002             case FuzzErrorMetric:
01003             case MeanAbsoluteErrorMetric:
01004             case MeanSquaredErrorMetric:
01005             case RootMeanSquaredErrorMetric:
01006             case PeakAbsoluteErrorMetric:
01007             {
01008               (void) FormatLocaleFile(stderr,"%g (%g)",QuantumRange*distortion,
01009                 (double) distortion);
01010               if ((reconstruct_image->columns != image->columns) ||
01011                   (reconstruct_image->rows != image->rows))
01012                 (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
01013                   difference_image->page.x,(double) difference_image->page.y);
01014               (void) FormatLocaleFile(stderr,"\n");
01015               break;
01016             }
01017             case AbsoluteErrorMetric:
01018             case NormalizedCrossCorrelationErrorMetric:
01019             case PeakSignalToNoiseRatioMetric:
01020             {
01021               (void) FormatLocaleFile(stderr,"%g",distortion);
01022               if ((reconstruct_image->columns != image->columns) ||
01023                   (reconstruct_image->rows != image->rows))
01024                 (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
01025                   difference_image->page.x,(double) difference_image->page.y);
01026               (void) FormatLocaleFile(stderr,"\n");
01027               break;
01028             }
01029             case MeanErrorPerPixelMetric:
01030             {
01031               (void) FormatLocaleFile(stderr,"%g (%g, %g)",distortion,
01032                 image->error.normalized_mean_error,
01033                 image->error.normalized_maximum_error);
01034               if ((reconstruct_image->columns != image->columns) ||
01035                   (reconstruct_image->rows != image->rows))
01036                 (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
01037                   difference_image->page.x,(double) difference_image->page.y);
01038               (void) FormatLocaleFile(stderr,"\n");
01039               break;
01040             }
01041             case UndefinedMetric:
01042               break;
01043           }
01044         }
01045       else
01046         {
01047           double
01048             *channel_distortion;
01049 
01050           channel_distortion=GetImageDistortions(image,reconstruct_image,
01051             metric,exception);
01052           (void) FormatLocaleFile(stderr,"Image: %s\n",image->filename);
01053           if ((reconstruct_image->columns != image->columns) ||
01054               (reconstruct_image->rows != image->rows))
01055             (void) FormatLocaleFile(stderr,"Offset: %.20g,%.20g\n",(double)
01056               difference_image->page.x,(double) difference_image->page.y);
01057           (void) FormatLocaleFile(stderr,"  Channel distortion: %s\n",
01058             CommandOptionToMnemonic(MagickMetricOptions,(ssize_t) metric));
01059           switch (metric)
01060           {
01061             case FuzzErrorMetric:
01062             case MeanAbsoluteErrorMetric:
01063             case MeanSquaredErrorMetric:
01064             case RootMeanSquaredErrorMetric:
01065             case PeakAbsoluteErrorMetric:
01066             {
01067               switch (image->colorspace)
01068               {
01069                 case RGBColorspace:
01070                 default:
01071                 {
01072                   (void) FormatLocaleFile(stderr,"    red: %g (%g)\n",
01073                     QuantumRange*channel_distortion[RedPixelChannel],
01074                     channel_distortion[RedPixelChannel]);
01075                   (void) FormatLocaleFile(stderr,"    green: %g (%g)\n",
01076                     QuantumRange*channel_distortion[GreenPixelChannel],
01077                     channel_distortion[GreenPixelChannel]);
01078                   (void) FormatLocaleFile(stderr,"    blue: %g (%g)\n",
01079                     QuantumRange*channel_distortion[BluePixelChannel],
01080                     channel_distortion[BluePixelChannel]);
01081                   if (image->matte != MagickFalse)
01082                     (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
01083                       QuantumRange*channel_distortion[AlphaPixelChannel],
01084                       channel_distortion[AlphaPixelChannel]);
01085                   break;
01086                 }
01087                 case CMYKColorspace:
01088                 {
01089                   (void) FormatLocaleFile(stderr,"    cyan: %g (%g)\n",
01090                     QuantumRange*channel_distortion[CyanPixelChannel],
01091                     channel_distortion[CyanPixelChannel]);
01092                   (void) FormatLocaleFile(stderr,"    magenta: %g (%g)\n",
01093                     QuantumRange*channel_distortion[MagentaPixelChannel],
01094                     channel_distortion[MagentaPixelChannel]);
01095                   (void) FormatLocaleFile(stderr,"    yellow: %g (%g)\n",
01096                     QuantumRange*channel_distortion[YellowPixelChannel],
01097                     channel_distortion[YellowPixelChannel]);
01098                   (void) FormatLocaleFile(stderr,"    black: %g (%g)\n",
01099                     QuantumRange*channel_distortion[BlackPixelChannel],
01100                     channel_distortion[BlackPixelChannel]);
01101                   if (image->matte != MagickFalse)
01102                     (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
01103                       QuantumRange*channel_distortion[AlphaPixelChannel],
01104                       channel_distortion[AlphaPixelChannel]);
01105                   break;
01106                 }
01107                 case GRAYColorspace:
01108                 {
01109                   (void) FormatLocaleFile(stderr,"    gray: %g (%g)\n",
01110                     QuantumRange*channel_distortion[GrayPixelChannel],
01111                     channel_distortion[GrayPixelChannel]);
01112                   if (image->matte != MagickFalse)
01113                     (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
01114                       QuantumRange*channel_distortion[AlphaPixelChannel],
01115                       channel_distortion[AlphaPixelChannel]);
01116                   break;
01117                 }
01118               }
01119               (void) FormatLocaleFile(stderr,"    all: %g (%g)\n",
01120                 QuantumRange*channel_distortion[MaxPixelChannels],
01121                 channel_distortion[MaxPixelChannels]);
01122               break;
01123             }
01124             case AbsoluteErrorMetric:
01125             case NormalizedCrossCorrelationErrorMetric:
01126             case PeakSignalToNoiseRatioMetric:
01127             {
01128               switch (image->colorspace)
01129               {
01130                 case RGBColorspace:
01131                 default:
01132                 {
01133                   (void) FormatLocaleFile(stderr,"    red: %g\n",
01134                     channel_distortion[RedPixelChannel]);
01135                   (void) FormatLocaleFile(stderr,"    green: %g\n",
01136                     channel_distortion[GreenPixelChannel]);
01137                   (void) FormatLocaleFile(stderr,"    blue: %g\n",
01138                     channel_distortion[BluePixelChannel]);
01139                   if (image->matte != MagickFalse)
01140                     (void) FormatLocaleFile(stderr,"    alpha: %g\n",
01141                       channel_distortion[AlphaPixelChannel]);
01142                   break;
01143                 }
01144                 case CMYKColorspace:
01145                 {
01146                   (void) FormatLocaleFile(stderr,"    cyan: %g\n",
01147                     channel_distortion[CyanPixelChannel]);
01148                   (void) FormatLocaleFile(stderr,"    magenta: %g\n",
01149                     channel_distortion[MagentaPixelChannel]);
01150                   (void) FormatLocaleFile(stderr,"    yellow: %g\n",
01151                     channel_distortion[YellowPixelChannel]);
01152                   (void) FormatLocaleFile(stderr,"    black: %g\n",
01153                     channel_distortion[BlackPixelChannel]);
01154                   if (image->matte != MagickFalse)
01155                     (void) FormatLocaleFile(stderr,"    alpha: %g\n",
01156                       channel_distortion[AlphaPixelChannel]);
01157                   break;
01158                 }
01159                 case GRAYColorspace:
01160                 {
01161                   (void) FormatLocaleFile(stderr,"    gray: %g\n",
01162                     channel_distortion[GrayPixelChannel]);
01163                   if (image->matte != MagickFalse)
01164                     (void) FormatLocaleFile(stderr,"    alpha: %g\n",
01165                       channel_distortion[AlphaPixelChannel]);
01166                   break;
01167                 }
01168               }
01169               (void) FormatLocaleFile(stderr,"    all: %g\n",
01170                 channel_distortion[MaxPixelChannels]);
01171               break;
01172             }
01173             case MeanErrorPerPixelMetric:
01174             {
01175               (void) FormatLocaleFile(stderr,"    %g (%g, %g)\n",
01176                 channel_distortion[MaxPixelChannels],
01177                 image->error.normalized_mean_error,
01178                 image->error.normalized_maximum_error);
01179               break;
01180             }
01181             case UndefinedMetric:
01182               break;
01183           }
01184           channel_distortion=(double *) RelinquishMagickMemory(
01185             channel_distortion);
01186         }
01187       status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
01188       if ((metadata != (char **) NULL) && (format != (char *) NULL))
01189         {
01190           char
01191             *text;
01192 
01193           text=InterpretImageProperties(image_info,difference_image,format,
01194             exception);
01195           if (text == (char *) NULL)
01196             ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
01197               GetExceptionMessage(errno));
01198           (void) ConcatenateString(&(*metadata),text);
01199           (void) ConcatenateString(&(*metadata),"\n");
01200           text=DestroyString(text);
01201         }
01202       difference_image=DestroyImageList(difference_image);
01203     }
01204   DestroyCompare();
01205   return(status != 0 ? MagickTrue : MagickFalse);
01206 }