]> granicus.if.org Git - imagemagick/blobdiff - MagickWand/compare.c
Fixed compiler warning.
[imagemagick] / MagickWand / compare.c
index ad328ca1200e56cc895a5b8e1047cad4da4cb51f..1a49cb5a669f817e992eb35e8faad70e545fdd70 100644 (file)
 %                         Image Comparison Methods                            %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                               December 2003                                 %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  CompareImageCommand() compares two images and returns the difference between
+%  CompareImagesCommand() compares two images and returns the difference between
 %  them as a distortion metric and as a new image visually annotating their
 %  differences.
 %
-%  The format of the CompareImageCommand method is:
+%  The format of the CompareImagesCommand method is:
 %
-%      MagickBooleanType CompareImageCommand(ImageInfo *image_info,int argc,
+%      MagickBooleanType CompareImagesCommand(ImageInfo *image_info,int argc,
 %        char **argv,char **metadata,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
@@ -124,7 +124,6 @@ static MagickBooleanType CompareUsage(void)
       "                     de-emphasize pixel differences with this color",
       "-metric type         measure differences between images with this metric",
       "-monitor             monitor progress",
-      "-passphrase filename get the passphrase from this file",
       "-profile filename    add, delete, or apply an image profile",
       "-quality value       JPEG/MIFF/PNG compression level",
       "-quiet               suppress all warning messages",
@@ -136,8 +135,12 @@ static MagickBooleanType CompareUsage(void)
       "-seed value          seed a new sequence of pseudo-random numbers",
       "-set attribute value set an image attribute",
       "-quality value       JPEG/MIFF/PNG compression level",
+      "-similarity-threshold value",
+      "                     minimum distortion for (sub)image match",
       "-size geometry       width and height of image",
       "-subimage-search     search for subimage",
+      "-synchronize         synchronize image to storage device",
+      "-taint               declare the image as modified",
       "-transparent-color color",
       "                     transparent color",
       "-type type           image type",
@@ -148,9 +151,7 @@ static MagickBooleanType CompareUsage(void)
       (char *) NULL
     };
 
-  (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
-  (void) printf("Copyright: %s\n",GetMagickCopyright());
-  (void) printf("Features: %s\n\n",GetMagickFeatures());
+  ListMagickVersion(stdout);
   (void) printf("Usage: %s [options ...] image reconstruct difference\n",
     GetClientName());
   (void) printf("\nImage Settings:\n");
@@ -160,7 +161,7 @@ static MagickBooleanType CompareUsage(void)
   for (p=miscellaneous; *p != (char *) NULL; p++)
     (void) printf("  %s\n",*p);
   (void) printf(
-    "\nBy default, the image format of `file' is determined by its magic\n");
+    "\nBy default, the image format of 'file' is determined by its magic\n");
   (void) printf(
     "number.  To specify a particular image format, precede the filename\n");
   (void) printf(
@@ -171,10 +172,12 @@ static MagickBooleanType CompareUsage(void)
   return(MagickFalse);
 }
 
-WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
+WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info,
   int argc,char **argv,char **metadata,ExceptionInfo *exception)
 {
+#define CompareEpsilon  (1.0e-06)
 #define DefaultDissimilarityThreshold  0.31830988618379067154
+#define DefaultSimilarityThreshold  (-1.0)
 #define DestroyCompare() \
 { \
   if (similarity_image != (Image *) NULL) \
@@ -197,7 +200,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
 #define ThrowCompareInvalidArgumentException(option,argument) \
 { \
   (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
-    "InvalidArgument","`%s': %s",option,argument); \
+    "InvalidArgument","'%s': %s",option,argument); \
   DestroyCompare(); \
   return(MagickFalse); \
 }
@@ -209,13 +212,11 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
   const char
     *format;
 
-  ChannelType
-    channels;
-
   double
     dissimilarity_threshold,
     distortion,
-    similarity_metric;
+    similarity_metric,
+    similarity_threshold;
 
   Image
     *difference_image,
@@ -262,26 +263,21 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
       if ((LocaleCompare("version",option+1) == 0) ||
           (LocaleCompare("-version",option+1) == 0))
         {
-          (void) FormatLocaleFile(stdout,"Version: %s\n",
-            GetMagickVersion((size_t *) NULL));
-          (void) FormatLocaleFile(stdout,"Copyright: %s\n",
-            GetMagickCopyright());
-          (void) FormatLocaleFile(stdout,"Features: %s\n\n",
-            GetMagickFeatures());
+          ListMagickVersion(stdout);
           return(MagickFalse);
         }
     }
   if (argc < 3)
     return(CompareUsage());
-  channels=CompositeChannels;
   difference_image=NewImageList();
   similarity_image=NewImageList();
   dissimilarity_threshold=DefaultDissimilarityThreshold;
+  similarity_threshold=DefaultSimilarityThreshold;
   distortion=0.0;
   format=(char *) NULL;
   j=1;
   k=0;
-  metric=UndefinedMetric;
+  metric=UndefinedErrorMetric;
   NewImageStack();
   option=(char *) NULL;
   pend=MagickFalse;
@@ -329,8 +325,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
         filename=argv[i];
         if ((LocaleCompare(filename,"--") == 0) && (i < (ssize_t) (argc-1)))
           filename=argv[++i];
-        (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
-        images=ReadImages(image_info,exception);
+        images=ReadImages(image_info,filename,exception);
         status&=(images != (Image *) NULL) &&
           (exception->severity < ErrorException);
         if (images == (Image *) NULL)
@@ -353,9 +348,9 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
             i++;
             if (i == (ssize_t) argc)
               ThrowCompareException(OptionError,"MissingArgument",option);
-            type=ParseCommandOption(MagickAlphaOptions,MagickFalse,argv[i]);
+            type=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,argv[i]);
             if (type < 0)
-              ThrowCompareException(OptionError,"UnrecognizedAlphaChannelType",
+              ThrowCompareException(OptionError,"UnrecognizedAlphaChannelOption",
                 argv[i]);
             break;
           }
@@ -397,7 +392,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
             if (channel < 0)
               ThrowCompareException(OptionError,"UnrecognizedChannelType",
                 argv[i]);
-            channels=(ChannelType) channel;
+            SetPixelChannelMask(image,(ChannelType) channel);
             break;
           }
         if (LocaleCompare("colorspace",option+1) == 0)
@@ -533,8 +528,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
             if (*option == '+')
               dissimilarity_threshold=DefaultDissimilarityThreshold;
             else
-              dissimilarity_threshold=InterpretLocaleValue(argv[i],
-                (char **) NULL);
+              dissimilarity_threshold=StringToDouble(argv[i],(char **) NULL);
             break;
           }
         if (LocaleCompare("duration",option+1) == 0)
@@ -664,7 +658,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
             i++;
             if (i == (ssize_t) argc)
               ThrowCompareException(OptionError,"MissingArgument",option);
-            value=InterpretLocaleValue(argv[i],&p);
+            value=StringToDouble(argv[i],&p);
             (void) value;
             if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0))
               ThrowCompareInvalidArgumentException(option,argv[i]);
@@ -735,15 +729,6 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
       }
       case 'p':
       {
-        if (LocaleCompare("passphrase",option+1) == 0)
-          {
-            if (*option == '+')
-              break;
-            i++;
-            if (i == (ssize_t) argc)
-              ThrowCompareException(OptionError,"MissingArgument",option);
-            break;
-          }
         if (LocaleCompare("profile",option+1) == 0)
           {
             i++;
@@ -834,6 +819,21 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
               ThrowCompareException(OptionError,"MissingArgument",option);
             break;
           }
+        if (LocaleCompare("similarity-threshold",option+1) == 0)
+          {
+            if (*option == '+')
+              break;
+            i++;
+            if (i == (ssize_t) argc)
+              ThrowCompareException(OptionError,"MissingArgument",option);
+            if (IsGeometry(argv[i]) == MagickFalse)
+              ThrowCompareInvalidArgumentException(option,argv[i]);
+            if (*option == '+')
+              similarity_threshold=DefaultSimilarityThreshold;
+            else
+              similarity_threshold=StringToDouble(argv[i],(char **) NULL);
+            break;
+          }
         if (LocaleCompare("size",option+1) == 0)
           {
             if (*option == '+')
@@ -897,12 +897,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
         if ((LocaleCompare("version",option+1) == 0) ||
             (LocaleCompare("-version",option+1) == 0))
           {
-            (void) FormatLocaleFile(stdout,"Version: %s\n",
-              GetMagickVersion((size_t *) NULL));
-            (void) FormatLocaleFile(stdout,"Copyright: %s\n",
-              GetMagickCopyright());
-            (void) FormatLocaleFile(stdout,"Features: %s\n\n",
-              GetMagickFeatures());
+            ListMagickVersion(stdout);
             break;
           }
         if (LocaleCompare("virtual-pixel",option+1) == 0)
@@ -945,21 +940,29 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
     ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
   image=GetImageFromList(image,0);
   reconstruct_image=GetImageFromList(image,1);
+  offset.x=0;
+  offset.y=0;
   if (subimage_search != MagickFalse)
     {
-      similarity_image=SimilarityImage(image,reconstruct_image,&offset,
-        &similarity_metric,exception);
+      similarity_image=SimilarityImage(image,reconstruct_image,metric,
+        similarity_threshold,&offset,&similarity_metric,exception);
       if (similarity_metric > dissimilarity_threshold)
         ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename);
     }
   if ((reconstruct_image->columns == image->columns) &&
-      (reconstruct_image->rows == image->rows))
-    difference_image=CompareImageChannels(image,reconstruct_image,channels,
-      metric,&distortion,exception);
+       (reconstruct_image->rows == image->rows))
+    difference_image=CompareImages(image,reconstruct_image,metric,&distortion,
+      exception);
   else
     if (similarity_image == (Image *) NULL)
-      ThrowCompareException(OptionError,"ImageWidthsOrHeightsDiffer",
-        image->filename)
+      {
+        if (metric == PerceptualHashErrorMetric)
+          difference_image=CompareImages(image,reconstruct_image,metric,
+            &distortion,exception);
+        else
+          ThrowCompareException(OptionError,"ImageWidthsOrHeightsDiffer",
+            image->filename);
+      }
     else
       {
         Image
@@ -970,20 +973,42 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
         */
         composite_image=CloneImage(image,0,0,MagickTrue,exception);
         if (composite_image == (Image *) NULL)
-          difference_image=CompareImageChannels(image,reconstruct_image,
-            channels,metric,&distortion,exception);
+          difference_image=CompareImages(image,reconstruct_image,metric,
+            &distortion,exception);
         else
           {
-            (void) CompositeImage(composite_image,CopyCompositeOp,
-              reconstruct_image,offset.x,offset.y);
-            difference_image=CompareImageChannels(image,composite_image,
-              channels,metric,&distortion,exception);
+            Image
+              *distort_image;
+
+            RectangleInfo
+              page;
+
+            (void) CompositeImage(composite_image,reconstruct_image,
+              CopyCompositeOp,MagickTrue,offset.x,offset.y,exception);
+            difference_image=CompareImages(image,composite_image,metric,
+              &distortion,exception);
             if (difference_image != (Image *) NULL)
               {
                 difference_image->page.x=offset.x;
                 difference_image->page.y=offset.y;
               }
             composite_image=DestroyImage(composite_image);
+            page.width=reconstruct_image->columns;
+            page.height=reconstruct_image->rows;
+            page.x=offset.x;
+            page.y=offset.y;
+            distort_image=CropImage(image,&page,exception);
+            if (distort_image != (Image *) NULL)
+              {
+                Image
+                  *sans_image;
+
+                sans_image=CompareImages(distort_image,reconstruct_image,metric,
+                  &distortion,exception);
+                distort_image=DestroyImage(distort_image);
+                if (sans_image != (Image *) NULL)
+                  sans_image=DestroyImage(sans_image);
+              }
           }
         if (difference_image != (Image *) NULL)
           {
@@ -996,7 +1021,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
   else
     {
       if (image_info->verbose != MagickFalse)
-        (void) IsImagesEqual(image,reconstruct_image);
+        (void) IsImagesEqual(image,reconstruct_image,exception);
       if (*difference_image->magick == '\0')
         (void) CopyMagickString(difference_image->magick,image->magick,
           MaxTextExtent);
@@ -1007,53 +1032,42 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
             case FuzzErrorMetric:
             case MeanAbsoluteErrorMetric:
             case MeanSquaredErrorMetric:
-            case RootMeanSquaredErrorMetric:
             case PeakAbsoluteErrorMetric:
+            case RootMeanSquaredErrorMetric:
             {
               (void) FormatLocaleFile(stderr,"%g (%g)",QuantumRange*distortion,
                 (double) distortion);
-              if ((reconstruct_image->columns != image->columns) ||
-                  (reconstruct_image->rows != image->rows))
-                (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
-                  difference_image->page.x,(double) difference_image->page.y);
-              (void) FormatLocaleFile(stderr,"\n");
               break;
             }
             case AbsoluteErrorMetric:
             case NormalizedCrossCorrelationErrorMetric:
-            case PeakSignalToNoiseRatioMetric:
+            case PeakSignalToNoiseRatioErrorMetric:
+            case PerceptualHashErrorMetric:
             {
               (void) FormatLocaleFile(stderr,"%g",distortion);
-              if ((reconstruct_image->columns != image->columns) ||
-                  (reconstruct_image->rows != image->rows))
-                (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
-                  difference_image->page.x,(double) difference_image->page.y);
-              (void) FormatLocaleFile(stderr,"\n");
               break;
             }
-            case MeanErrorPerPixelMetric:
+            case MeanErrorPerPixelErrorMetric:
             {
               (void) FormatLocaleFile(stderr,"%g (%g, %g)",distortion,
                 image->error.normalized_mean_error,
                 image->error.normalized_maximum_error);
-              if ((reconstruct_image->columns != image->columns) ||
-                  (reconstruct_image->rows != image->rows))
-                (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
-                  difference_image->page.x,(double) difference_image->page.y);
-              (void) FormatLocaleFile(stderr,"\n");
               break;
             }
-            case UndefinedMetric:
+            case UndefinedErrorMetric:
               break;
           }
+          if (subimage_search != MagickFalse)
+            (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
+              difference_image->page.x,(double) difference_image->page.y);
         }
       else
         {
           double
             *channel_distortion;
 
-          channel_distortion=GetImageChannelDistortions(image,reconstruct_image,
-            metric,&image->exception);
+          channel_distortion=GetImageDistortions(image,reconstruct_image,
+            metric,exception);
           (void) FormatLocaleFile(stderr,"Image: %s\n",image->filename);
           if ((reconstruct_image->columns != image->columns) ||
               (reconstruct_image->rows != image->rows))
@@ -1066,8 +1080,8 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
             case FuzzErrorMetric:
             case MeanAbsoluteErrorMetric:
             case MeanSquaredErrorMetric:
-            case RootMeanSquaredErrorMetric:
             case PeakAbsoluteErrorMetric:
+            case RootMeanSquaredErrorMetric:
             {
               switch (image->colorspace)
               {
@@ -1075,60 +1089,61 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
                 default:
                 {
                   (void) FormatLocaleFile(stderr,"    red: %g (%g)\n",
-                    QuantumRange*channel_distortion[RedChannel],
-                    channel_distortion[RedChannel]);
+                    QuantumRange*channel_distortion[RedPixelChannel],
+                    channel_distortion[RedPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    green: %g (%g)\n",
-                    QuantumRange*channel_distortion[GreenChannel],
-                    channel_distortion[GreenChannel]);
+                    QuantumRange*channel_distortion[GreenPixelChannel],
+                    channel_distortion[GreenPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    blue: %g (%g)\n",
-                    QuantumRange*channel_distortion[BlueChannel],
-                    channel_distortion[BlueChannel]);
-                  if (image->matte != MagickFalse)
+                    QuantumRange*channel_distortion[BluePixelChannel],
+                    channel_distortion[BluePixelChannel]);
+                  if (image->alpha_trait == BlendPixelTrait)
                     (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
-                      QuantumRange*channel_distortion[OpacityChannel],
-                      channel_distortion[OpacityChannel]);
+                      QuantumRange*channel_distortion[AlphaPixelChannel],
+                      channel_distortion[AlphaPixelChannel]);
                   break;
                 }
                 case CMYKColorspace:
                 {
                   (void) FormatLocaleFile(stderr,"    cyan: %g (%g)\n",
-                    QuantumRange*channel_distortion[CyanChannel],
-                    channel_distortion[CyanChannel]);
+                    QuantumRange*channel_distortion[CyanPixelChannel],
+                    channel_distortion[CyanPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    magenta: %g (%g)\n",
-                    QuantumRange*channel_distortion[MagentaChannel],
-                    channel_distortion[MagentaChannel]);
+                    QuantumRange*channel_distortion[MagentaPixelChannel],
+                    channel_distortion[MagentaPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    yellow: %g (%g)\n",
-                    QuantumRange*channel_distortion[YellowChannel],
-                    channel_distortion[YellowChannel]);
+                    QuantumRange*channel_distortion[YellowPixelChannel],
+                    channel_distortion[YellowPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    black: %g (%g)\n",
-                    QuantumRange*channel_distortion[BlackChannel],
-                    channel_distortion[BlackChannel]);
-                  if (image->matte != MagickFalse)
+                    QuantumRange*channel_distortion[BlackPixelChannel],
+                    channel_distortion[BlackPixelChannel]);
+                  if (image->alpha_trait == BlendPixelTrait)
                     (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
-                      QuantumRange*channel_distortion[OpacityChannel],
-                      channel_distortion[OpacityChannel]);
+                      QuantumRange*channel_distortion[AlphaPixelChannel],
+                      channel_distortion[AlphaPixelChannel]);
                   break;
                 }
                 case GRAYColorspace:
                 {
                   (void) FormatLocaleFile(stderr,"    gray: %g (%g)\n",
-                    QuantumRange*channel_distortion[GrayChannel],
-                    channel_distortion[GrayChannel]);
-                  if (image->matte != MagickFalse)
+                    QuantumRange*channel_distortion[GrayPixelChannel],
+                    channel_distortion[GrayPixelChannel]);
+                  if (image->alpha_trait == BlendPixelTrait)
                     (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
-                      QuantumRange*channel_distortion[OpacityChannel],
-                      channel_distortion[OpacityChannel]);
+                      QuantumRange*channel_distortion[AlphaPixelChannel],
+                      channel_distortion[AlphaPixelChannel]);
                   break;
                 }
               }
               (void) FormatLocaleFile(stderr,"    all: %g (%g)\n",
-                QuantumRange*channel_distortion[CompositeChannels],
-                channel_distortion[CompositeChannels]);
+                QuantumRange*channel_distortion[MaxPixelChannels],
+                channel_distortion[MaxPixelChannels]);
               break;
             }
             case AbsoluteErrorMetric:
             case NormalizedCrossCorrelationErrorMetric:
-            case PeakSignalToNoiseRatioMetric:
+            case PeakSignalToNoiseRatioErrorMetric:
+            case PerceptualHashErrorMetric:
             {
               switch (image->colorspace)
               {
@@ -1136,58 +1151,61 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
                 default:
                 {
                   (void) FormatLocaleFile(stderr,"    red: %g\n",
-                    channel_distortion[RedChannel]);
+                    channel_distortion[RedPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    green: %g\n",
-                    channel_distortion[GreenChannel]);
+                    channel_distortion[GreenPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    blue: %g\n",
-                    channel_distortion[BlueChannel]);
-                  if (image->matte != MagickFalse)
+                    channel_distortion[BluePixelChannel]);
+                  if (image->alpha_trait == BlendPixelTrait)
                     (void) FormatLocaleFile(stderr,"    alpha: %g\n",
-                      channel_distortion[OpacityChannel]);
+                      channel_distortion[AlphaPixelChannel]);
                   break;
                 }
                 case CMYKColorspace:
                 {
                   (void) FormatLocaleFile(stderr,"    cyan: %g\n",
-                    channel_distortion[CyanChannel]);
+                    channel_distortion[CyanPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    magenta: %g\n",
-                    channel_distortion[MagentaChannel]);
+                    channel_distortion[MagentaPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    yellow: %g\n",
-                    channel_distortion[YellowChannel]);
+                    channel_distortion[YellowPixelChannel]);
                   (void) FormatLocaleFile(stderr,"    black: %g\n",
-                    channel_distortion[BlackChannel]);
-                  if (image->matte != MagickFalse)
+                    channel_distortion[BlackPixelChannel]);
+                  if (image->alpha_trait == BlendPixelTrait)
                     (void) FormatLocaleFile(stderr,"    alpha: %g\n",
-                      channel_distortion[OpacityChannel]);
+                      channel_distortion[AlphaPixelChannel]);
                   break;
                 }
                 case GRAYColorspace:
                 {
                   (void) FormatLocaleFile(stderr,"    gray: %g\n",
-                    channel_distortion[GrayChannel]);
-                  if (image->matte != MagickFalse)
+                    channel_distortion[GrayPixelChannel]);
+                  if (image->alpha_trait == BlendPixelTrait)
                     (void) FormatLocaleFile(stderr,"    alpha: %g\n",
-                      channel_distortion[OpacityChannel]);
+                      channel_distortion[AlphaPixelChannel]);
                   break;
                 }
               }
               (void) FormatLocaleFile(stderr,"    all: %g\n",
-                channel_distortion[CompositeChannels]);
+                channel_distortion[MaxPixelChannels]);
               break;
             }
-            case MeanErrorPerPixelMetric:
+            case MeanErrorPerPixelErrorMetric:
             {
               (void) FormatLocaleFile(stderr,"    %g (%g, %g)\n",
-                channel_distortion[CompositeChannels],
+                channel_distortion[MaxPixelChannels],
                 image->error.normalized_mean_error,
                 image->error.normalized_maximum_error);
               break;
             }
-            case UndefinedMetric:
+            case UndefinedErrorMetric:
               break;
           }
           channel_distortion=(double *) RelinquishMagickMemory(
             channel_distortion);
+          if (subimage_search != MagickFalse)
+            (void) FormatLocaleFile(stderr,"   Offset: %.20g,%.20g\n",(double)
+              difference_image->page.x,(double) difference_image->page.y);
         }
       status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
       if ((metadata != (char **) NULL) && (format != (char *) NULL))
@@ -1195,16 +1213,25 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
           char
             *text;
 
-          text=InterpretImageProperties(image_info,difference_image,format);
+          text=InterpretImageProperties(image_info,difference_image,format,
+            exception);
           if (text == (char *) NULL)
             ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
               GetExceptionMessage(errno));
           (void) ConcatenateString(&(*metadata),text);
-          (void) ConcatenateString(&(*metadata),"\n");
           text=DestroyString(text);
         }
       difference_image=DestroyImageList(difference_image);
     }
   DestroyCompare();
+  if ((metric == NormalizedCrossCorrelationErrorMetric) ||
+      (metric == UndefinedErrorMetric))
+    {
+      if (fabs(distortion-1.0) > CompareEpsilon)
+        (void) SetImageOption(image_info,"compare:dissimilar","true");
+    }
+  else
+    if (fabs(distortion) > CompareEpsilon)
+      (void) SetImageOption(image_info,"compare:dissimilar","true");
   return(status != 0 ? MagickTrue : MagickFalse);
 }