PageRenderTime 10ms CodeModel.GetById 2ms app.highlight 64ms RepoModel.GetById 2ms app.codeStats 0ms

/scripts/ImageMagick-6.6.2-6/wand/compare.c

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