]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/identify.c
(no commit message)
[imagemagick] / MagickCore / identify.c
index 4c78109a192332bbbe7cc2d952c7983cc516da99..0c9c0095df3150aaa562f9f4da81b4bc090f88f5 100644 (file)
 %               Identify an Image Format and Characteristics.                 %
 %                                                                             %
 %                           Software Design                                   %
-%                             John Cristy                                     %
+%                                Cristy                                       %
 %                            September 1994                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2008 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  %
 #include "MagickCore/string_.h"
 #include "MagickCore/string-private.h"
 #include "MagickCore/timer.h"
+#include "MagickCore/token.h"
 #include "MagickCore/utility.h"
 #include "MagickCore/utility-private.h"
 #include "MagickCore/version.h"
-#if defined(MAGICKCORE_LCMS_DELEGATE)
-#if defined(MAGICKCORE_HAVE_LCMS_LCMS2_H)
-#include <lcms/lcms2.h>
-#elif defined(MAGICKCORE_HAVE_LCMS2_H)
-#include "lcms2.h"
-#elif defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
-#include <lcms/lcms.h>
-#else
-#include "lcms.h"
-#endif
-#endif
-\f
-/*
-  Define declarations.
-*/
-#if defined(MAGICKCORE_LCMS_DELEGATE)
-#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
-#define cmsUInt32Number  DWORD
-#endif
-#endif
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 */
 
+static ChannelStatistics *GetLocationStatistics(const Image *image,
+  const StatisticType type,ExceptionInfo *exception)
+{
+  ChannelStatistics
+    *channel_statistics;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
+    MaxPixelChannels+1,sizeof(*channel_statistics));
+  if (channel_statistics == (ChannelStatistics *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
+    sizeof(*channel_statistics));
+  for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
+  {
+    switch (type)
+    {
+      case MaximumStatistic:
+      default:
+      {
+        channel_statistics[i].maxima=(-MagickMaximumValue);
+        break;
+      }
+      case MinimumStatistic:
+      {
+        channel_statistics[i].minima=MagickMaximumValue;
+        break;
+      }
+    }
+  }
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      register ssize_t
+        i;
+
+      if (GetPixelReadMask(image,p) == 0)
+        {
+          p+=GetPixelChannels(image);
+          continue;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel channel=GetPixelChannelChannel(image,i);
+        PixelTrait traits=GetPixelChannelTraits(image,channel);
+        if (traits == UndefinedPixelTrait)
+          continue;
+        switch (type)
+        {
+          case MaximumStatistic:
+          default:
+          {
+            if ((double) p[i] > channel_statistics[channel].maxima)
+              channel_statistics[channel].maxima=(double) p[i];
+            break;
+          }
+          case MinimumStatistic:
+          {
+            if ((double) p[i] < channel_statistics[channel].minima)
+              channel_statistics[channel].minima=(double) p[i];
+            break;
+          }
+        }
+      }
+      p+=GetPixelChannels(image);
+    }
+  }
+  return(channel_statistics);
+}
+
 static ssize_t PrintChannelFeatures(FILE *file,const PixelChannel channel,
   const char *name,const ChannelFeatures *channel_features)
 {
@@ -164,7 +234,7 @@ static ssize_t PrintChannelFeatures(FILE *file,const PixelChannel channel,
   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
   "      Correlation:\n" \
   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
-  "      Sum of Squares: Variance:\n" \
+  "      Sum of Squares Variance:\n" \
   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
   "      Inverse Difference Moment:\n" \
   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
@@ -208,6 +278,127 @@ static ssize_t PrintChannelFeatures(FILE *file,const PixelChannel channel,
   return(n);
 }
 
+static ssize_t PrintChannelLocations(FILE *file,const Image *image,
+  const PixelChannel channel,const char *name,const StatisticType type,
+  const size_t max_locations,const ChannelStatistics *channel_statistics)
+{
+  double
+    target;
+
+  ExceptionInfo
+    *exception;
+
+  ssize_t
+    n,
+    y;
+
+  switch (type)
+  {
+    case MaximumStatistic:
+    default:
+    {
+      target=channel_statistics[channel].maxima;
+      break;
+    }
+    case MinimumStatistic:
+    {
+      target=channel_statistics[channel].minima;
+      break;
+    }
+  }
+  (void) FormatLocaleFile(file,"  %s: %.*g (%.*g)",name,GetMagickPrecision(),
+    target,GetMagickPrecision(),QuantumScale*target);
+  exception=AcquireExceptionInfo();
+  n=0;
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *p;
+
+    ssize_t
+      offset,
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickBooleanType
+        match;
+
+      PixelTrait traits=GetPixelChannelTraits(image,channel);
+      if (traits == UndefinedPixelTrait)
+        continue;
+      offset=GetPixelChannelOffset(image,channel);
+      match=fabs((double) p[offset]-target) < 0.5 ? MagickTrue : MagickFalse;
+      if (match != MagickFalse)
+        {
+          if ((max_locations != 0) && (n >= (ssize_t) max_locations))
+            break;
+          (void) FormatLocaleFile(file," %.20g,%.20g",(double) x,(double) y);
+          n++;
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (x < (ssize_t) image->columns)
+      break;
+  }
+  (void) FormatLocaleFile(file,"\n");
+  return(n);
+}
+
+static ssize_t PrintChannelMoments(FILE *file,const PixelChannel channel,
+  const char *name,const double scale,const ChannelMoments *channel_moments)
+{
+  double
+    powers[8] = { 1.0, 2.0, 3.0, 3.0, 6.0, 4.0, 6.0, 4.0 };
+
+  register ssize_t
+    i;
+
+  ssize_t
+    n;
+
+  n=FormatLocaleFile(file,"    %s:\n",name);
+  n+=FormatLocaleFile(file,"      Centroid: %.*g,%.*g\n",
+    GetMagickPrecision(),channel_moments[channel].centroid.x,
+    GetMagickPrecision(),channel_moments[channel].centroid.y);
+  n+=FormatLocaleFile(file,"      Ellipse Semi-Major/Minor axis: %.*g,%.*g\n",
+    GetMagickPrecision(),channel_moments[channel].ellipse_axis.x,
+    GetMagickPrecision(),channel_moments[channel].ellipse_axis.y);
+  n+=FormatLocaleFile(file,"      Ellipse angle: %.*g\n",
+    GetMagickPrecision(),channel_moments[channel].ellipse_angle);
+  n+=FormatLocaleFile(file,"      Ellipse eccentricity: %.*g\n",
+    GetMagickPrecision(),channel_moments[channel].ellipse_eccentricity);
+  n+=FormatLocaleFile(file,"      Ellipse intensity: %.*g (%.*g)\n",
+    GetMagickPrecision(),pow(scale,powers[0])*
+    channel_moments[channel].ellipse_intensity,GetMagickPrecision(),
+    channel_moments[channel].ellipse_intensity);
+  for (i=0; i < 8; i++)
+    n+=FormatLocaleFile(file,"      I%.20g: %.*g (%.*g)\n",i+1.0,
+      GetMagickPrecision(),channel_moments[channel].I[i]/pow(scale,powers[i]),
+      GetMagickPrecision(),channel_moments[channel].I[i]);
+  return(n);
+}
+
+static ssize_t PrintChannelPerceptualHash(FILE *file,const ChannelType channel,
+  const char *name,const ChannelPerceptualHash *channel_phash)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    n;
+
+  n=FormatLocaleFile(file,"    %s:\n",name);
+  for (i=0; i < 7; i++)
+    n+=FormatLocaleFile(file,"      PH%.20g: %.*g, %.*g\n",i+1.0,
+      GetMagickPrecision(),channel_phash[channel].P[i],
+      GetMagickPrecision(),channel_phash[channel].Q[i]);
+  return(n);
+}
+
 static ssize_t PrintChannelStatistics(FILE *file,const PixelChannel channel,
   const char *name,const double scale,
   const ChannelStatistics *channel_statistics)
@@ -243,6 +434,12 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
   ChannelFeatures
     *channel_features;
 
+  ChannelMoments
+    *channel_moments;
+
+  ChannelPerceptualHash
+    *channel_phash;
+
   ChannelStatistics
     *channel_statistics;
 
@@ -251,6 +448,7 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
 
   const char
     *artifact,
+    *locate,
     *name,
     *property,
     *registry,
@@ -261,6 +459,7 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
 
   double
     elapsed_time,
+    scale,
     user_time;
 
   ImageType
@@ -277,8 +476,7 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
     x;
 
   size_t
-    distance,
-    scale;
+    distance;
 
   ssize_t
     y;
@@ -289,6 +487,73 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if (file == (FILE *) NULL)
     file=stdout;
+  locate=GetImageArtifact(image,"identify:locate");
+  if (locate != (const char *) NULL)
+    {
+      const char
+        *limit;
+
+      size_t
+        max_locations;
+
+      StatisticType
+        type;
+
+      /*
+        Display minimum, maximum, or mean pixel locations.
+      */
+      type=(StatisticType) ParseCommandOption(MagickStatisticOptions,
+        MagickFalse,locate);
+      limit=GetImageArtifact(image,"identify:limit");
+      max_locations=0;
+      if (limit != (const char *) NULL)
+        max_locations=StringToUnsignedLong(limit);
+      channel_statistics=GetLocationStatistics(image,type,exception);
+      if (channel_statistics == (ChannelStatistics *) NULL)
+        return(MagickFalse);
+      colorspace=image->colorspace;
+      if (IsImageGray(image,exception) != MagickFalse)
+        colorspace=GRAYColorspace;
+      (void) FormatLocaleFile(file,"Channel %s locations:\n",locate);
+      switch (colorspace)
+      {
+        case RGBColorspace:
+        default:
+        {
+          (void) PrintChannelLocations(file,image,RedPixelChannel,"Red",
+            type,max_locations,channel_statistics);
+          (void) PrintChannelLocations(file,image,GreenPixelChannel,"Green",
+            type,max_locations,channel_statistics);
+          (void) PrintChannelLocations(file,image,BluePixelChannel,"Blue",
+            type,max_locations,channel_statistics);
+          break;
+        }
+        case CMYKColorspace:
+        {
+          (void) PrintChannelLocations(file,image,CyanPixelChannel,"Cyan",
+            type,max_locations,channel_statistics);
+          (void) PrintChannelLocations(file,image,MagentaPixelChannel,"Magenta",
+            type,max_locations,channel_statistics);
+          (void) PrintChannelLocations(file,image,YellowPixelChannel,"Yellow",
+            type,max_locations,channel_statistics);
+          (void) PrintChannelLocations(file,image,BlackPixelChannel,"Black",
+            type,max_locations,channel_statistics);
+          break;
+        }
+        case GRAYColorspace:
+        {
+          (void) PrintChannelLocations(file,image,GrayPixelChannel,"Gray",
+            type,max_locations,channel_statistics);
+          break;
+        }
+      }
+      if (image->alpha_trait == BlendPixelTrait)
+        (void) PrintChannelLocations(file,image,AlphaPixelChannel,"Alpha",
+          type,max_locations,channel_statistics);
+      channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
+        channel_statistics);
+      return(ferror(file) != 0 ? MagickFalse : MagickTrue);
+    }
   *format='\0';
   elapsed_time=GetElapsedTime(&image->timer);
   user_time=GetUserTime(&image->timer);
@@ -325,9 +590,11 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
       if (image->type != UndefinedType)
         (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic(
           MagickTypeOptions,(ssize_t) image->type));
+      if (image->colorspace != UndefinedColorspace)
+        (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic(
+          MagickColorspaceOptions,(ssize_t) image->colorspace));
       if (image->storage_class == DirectClass)
         {
-          (void) FormatLocaleFile(file,"DirectClass ");
           if (image->total_colors != 0)
             {
               (void) FormatMagickSize(image->total_colors,MagickFalse,format);
@@ -336,10 +603,10 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
         }
       else
         if (image->total_colors <= image->colors)
-          (void) FormatLocaleFile(file,"PseudoClass %.20gc ",(double)
+          (void) FormatLocaleFile(file,"%.20gc ",(double)
             image->colors);
         else
-          (void) FormatLocaleFile(file,"PseudoClass %.20g=>%.20gc ",(double)
+          (void) FormatLocaleFile(file,"%.20g=>%.20gc ",(double)
             image->total_colors,(double) image->colors);
       if (image->error.mean_error_per_pixel != 0.0)
         (void) FormatLocaleFile(file,"%.20g/%f/%fdb ",(double)
@@ -378,11 +645,15 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
       }
   magick_info=GetMagickInfo(image->magick,exception);
   if ((magick_info == (const MagickInfo *) NULL) ||
-      (*GetMagickDescription(magick_info) == '\0'))
+      (GetMagickDescription(magick_info) == (const char *) NULL))
     (void) FormatLocaleFile(file,"  Format: %s\n",image->magick);
   else
     (void) FormatLocaleFile(file,"  Format: %s (%s)\n",image->magick,
       GetMagickDescription(magick_info));
+  if ((magick_info == (const MagickInfo *) NULL) ||
+      (GetMagickMimeType(magick_info) != (const char *) NULL))
+    (void) FormatLocaleFile(file,"  Mime type: %s\n",GetMagickMimeType(
+      magick_info));
   (void) FormatLocaleFile(file,"  Class: %s\n",CommandOptionToMnemonic(
     MagickClassOptions,(ssize_t) image->storage_class));
   (void) FormatLocaleFile(file,"  Geometry: %.20gx%.20g%+.20g%+.20g\n",(double)
@@ -416,14 +687,25 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
   (void) FormatLocaleFile(file,"  Colorspace: %s\n",CommandOptionToMnemonic(
     MagickColorspaceOptions,(ssize_t) image->colorspace));
   channel_statistics=(ChannelStatistics *) NULL;
+  channel_moments=(ChannelMoments *) NULL;
+  channel_phash=(ChannelPerceptualHash *) NULL;
   channel_features=(ChannelFeatures *) NULL;
   colorspace=image->colorspace;
+  scale=1.0;
   if (ping == MagickFalse)
     {
       size_t
         depth;
 
       channel_statistics=GetImageStatistics(image,exception);
+      if (channel_statistics == (ChannelStatistics *) NULL)
+        return(MagickFalse);
+      artifact=GetImageArtifact(image,"identify:moments");
+      if (artifact != (const char *) NULL)
+        {
+          channel_moments=GetImageMoments(image,exception);
+          channel_phash=GetImagePerceptualHash(image,exception);
+        }
       artifact=GetImageArtifact(image,"identify:features");
       if (artifact != (const char *) NULL)
         {
@@ -445,44 +727,46 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
         case RGBColorspace:
         default:
         {
-          (void) FormatLocaleFile(file,"    red: %.20g-bit\n",(double)
+          (void) FormatLocaleFile(file,"    Red: %.20g-bit\n",(double)
             channel_statistics[RedPixelChannel].depth);
-          (void) FormatLocaleFile(file,"    green: %.20g-bit\n",(double)
+          (void) FormatLocaleFile(file,"    Green: %.20g-bit\n",(double)
             channel_statistics[GreenPixelChannel].depth);
-          (void) FormatLocaleFile(file,"    blue: %.20g-bit\n",(double)
+          (void) FormatLocaleFile(file,"    Blue: %.20g-bit\n",(double)
             channel_statistics[BluePixelChannel].depth);
           break;
         }
         case CMYKColorspace:
         {
-          (void) FormatLocaleFile(file,"    cyan: %.20g-bit\n",(double)
+          (void) FormatLocaleFile(file,"    Cyan: %.20g-bit\n",(double)
             channel_statistics[CyanPixelChannel].depth);
-          (void) FormatLocaleFile(file,"    magenta: %.20g-bit\n",(double)
+          (void) FormatLocaleFile(file,"    Magenta: %.20g-bit\n",(double)
             channel_statistics[MagentaPixelChannel].depth);
-          (void) FormatLocaleFile(file,"    yellow: %.20g-bit\n",(double)
+          (void) FormatLocaleFile(file,"    Yellow: %.20g-bit\n",(double)
             channel_statistics[YellowPixelChannel].depth);
-          (void) FormatLocaleFile(file,"    black: %.20g-bit\n",(double)
+          (void) FormatLocaleFile(file,"    Black: %.20g-bit\n",(double)
             channel_statistics[BlackPixelChannel].depth);
           break;
         }
         case GRAYColorspace:
         {
-          (void) FormatLocaleFile(file,"    gray: %.20g-bit\n",(double)
+          (void) FormatLocaleFile(file,"    Gray: %.20g-bit\n",(double)
             channel_statistics[GrayPixelChannel].depth);
           break;
         }
       }
-      if (image->matte != MagickFalse)
+      if (image->alpha_trait == BlendPixelTrait)
         (void) FormatLocaleFile(file,"    alpha: %.20g-bit\n",(double)
           channel_statistics[AlphaPixelChannel].depth);
-      scale=1;
+      scale=1.0;
       if (image->depth <= MAGICKCORE_QUANTUM_DEPTH)
-        scale=QuantumRange/((size_t) QuantumRange >> ((size_t)
+        scale=(double) QuantumRange/((size_t) QuantumRange >> ((size_t)
           MAGICKCORE_QUANTUM_DEPTH-image->depth));
     }
   if (channel_statistics != (ChannelStatistics *) NULL)
     {
       (void) FormatLocaleFile(file,"  Channel statistics:\n");
+      (void) FormatLocaleFile(file,"    Pixels: %.20g\n",
+        channel_statistics[CompositePixelChannel].area);
       switch (colorspace)
       {
         case RGBColorspace:
@@ -515,7 +799,7 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
           break;
         }
       }
-      if (image->matte != MagickFalse)
+      if (image->alpha_trait == BlendPixelTrait)
         (void) PrintChannelStatistics(file,AlphaPixelChannel,"Alpha",1.0/
           scale,channel_statistics);
       if (colorspace != GRAYColorspace)
@@ -527,6 +811,69 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
       channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
         channel_statistics);
     }
+  if (channel_moments != (ChannelMoments *) NULL)
+    {
+      scale=(double) ((1UL << image->depth)-1);
+      (void) FormatLocaleFile(file,"  Channel moments:\n");
+      switch (colorspace)
+      {
+        case RGBColorspace:
+        default:
+        {
+          (void) PrintChannelMoments(file,RedPixelChannel,"Red",scale,
+            channel_moments);
+          (void) PrintChannelMoments(file,GreenPixelChannel,"Green",scale,
+            channel_moments);
+          (void) PrintChannelMoments(file,BluePixelChannel,"Blue",scale,
+            channel_moments);
+          break;
+        }
+        case CMYKColorspace:
+        {
+          (void) PrintChannelMoments(file,CyanPixelChannel,"Cyan",scale,
+            channel_moments);
+          (void) PrintChannelMoments(file,MagentaPixelChannel,"Magenta",scale,
+            channel_moments);
+          (void) PrintChannelMoments(file,YellowPixelChannel,"Yellow",scale,
+            channel_moments);
+          (void) PrintChannelMoments(file,BlackPixelChannel,"Black",scale,
+            channel_moments);
+          break;
+        }
+        case GRAYColorspace:
+        {
+          (void) PrintChannelMoments(file,GrayPixelChannel,"Gray",scale,
+            channel_moments);
+          break;
+        }
+      }
+      if (image->alpha_trait == BlendPixelTrait)
+        (void) PrintChannelMoments(file,AlphaPixelChannel,"Alpha",scale,
+          channel_moments);
+      if (colorspace != GRAYColorspace)
+        {
+          (void) FormatLocaleFile(file,"  Image moments:\n");
+          (void) PrintChannelMoments(file,(PixelChannel) MaxPixelChannels,
+            "Overall",scale,channel_moments);
+        }
+      channel_moments=(ChannelMoments *) RelinquishMagickMemory(
+        channel_moments);
+    }
+  if (channel_phash != (ChannelPerceptualHash *) NULL)
+    {
+      (void) FormatLocaleFile(file,"  Channel perceptual hash:\n");
+      (void) PrintChannelPerceptualHash(file,RedChannel,"Red, Hue",
+        channel_phash);
+      (void) PrintChannelPerceptualHash(file,GreenChannel,"Green, Chroma",
+        channel_phash);
+      (void) PrintChannelPerceptualHash(file,BlueChannel,"Blue, Luma",
+        channel_phash);
+      if (image->alpha_trait == BlendPixelTrait)
+        (void) PrintChannelPerceptualHash(file,AlphaChannel,"Alpha, Alpha",
+          channel_phash);
+      channel_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(
+        channel_phash);
+    }
   if (channel_features != (ChannelFeatures *) NULL)
     {
       (void) FormatLocaleFile(file,"  Channel features (horizontal, vertical, "
@@ -563,7 +910,7 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
           break;
         }
       }
-      if (image->matte != MagickFalse)
+      if (image->alpha_trait == BlendPixelTrait)
         (void) PrintChannelFeatures(file,AlphaPixelChannel,"Alpha",
           channel_features);
       channel_features=(ChannelFeatures *) RelinquishMagickMemory(
@@ -572,10 +919,11 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
   if (ping == MagickFalse)
     {
       if (image->colorspace == CMYKColorspace)
-        (void) FormatLocaleFile(file,"  Total ink density: %.0f%%\n",100.0*
-          GetImageTotalInkDensity(image,exception)/(double) QuantumRange);
+        (void) FormatLocaleFile(file,"  Total ink density: %*g%%\n",
+          GetMagickPrecision(),100.0*GetImageTotalInkDensity(image,exception)/
+          (double) QuantumRange);
       x=0;
-      if (image->matte != MagickFalse)
+      if (image->alpha_trait == BlendPixelTrait)
         {
           register const Quantum
             *p;
@@ -612,7 +960,6 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
               (void) FormatLocaleFile(file,"  %s\n",tuple);
             }
         }
-      artifact=GetImageArtifact(image,"identify:unique-colors");
       if (IsHistogramImage(image,exception) != MagickFalse)
         {
           (void) FormatLocaleFile(file,"  Colors: %.20g\n",(double)
@@ -621,15 +968,18 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
           (void) GetNumberColors(image,file,exception);
         }
       else
-        if ((artifact != (const char *) NULL) &&
-            (IsMagickTrue(artifact) != MagickFalse))
-          (void) FormatLocaleFile(file,"  Colors: %.20g\n",(double)
-            GetNumberColors(image,(FILE *) NULL,exception));
+        {
+          artifact=GetImageArtifact(image,"identify:unique-colors");
+          if (IfMagickTrue(IsStringTrue(artifact)))
+            (void) FormatLocaleFile(file,"  Colors: %.20g\n",(double)
+              GetNumberColors(image,(FILE *) NULL,exception));
+        }
     }
   if (image->storage_class == PseudoClass)
     {
-      (void) FormatLocaleFile(file,"  Colormap: %.20g\n",(double)
+      (void) FormatLocaleFile(file,"  Colormap entries: %.20g\n",(double)
         image->colors);
+      (void) FormatLocaleFile(file,"  Colormap:\n");
       if (image->colors <= 1024)
         {
           char
@@ -663,7 +1013,7 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
                 ConcatenateColorComponent(&pixel,BlackPixelChannel,
                   X11Compliance,tuple);
               }
-            if (pixel.matte != MagickFalse)
+            if (pixel.alpha_trait == BlendPixelTrait)
               {
                 (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
                 ConcatenateColorComponent(&pixel,AlphaPixelChannel,
@@ -716,8 +1066,6 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
     (void) FormatLocaleFile(file,"  Tile geometry: %.20gx%.20g%+.20g%+.20g\n",
       (double) image->extract_info.width,(double) image->extract_info.height,
       (double) image->extract_info.x,(double) image->extract_info.y);
-  (void) FormatLocaleFile(file,"  Interlace: %s\n",CommandOptionToMnemonic(
-    MagickInterlaceOptions,(ssize_t) image->interlace));
   (void) QueryColorname(image,&image->background_color,SVGCompliance,color,
     exception);
   (void) FormatLocaleFile(file,"  Background color: %s\n",color);
@@ -730,6 +1078,10 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
   (void) QueryColorname(image,&image->transparent_color,SVGCompliance,color,
     exception);
   (void) FormatLocaleFile(file,"  Transparent color: %s\n",color);
+  (void) FormatLocaleFile(file,"  Interlace: %s\n",CommandOptionToMnemonic(
+    MagickInterlaceOptions,(ssize_t) image->interlace));
+  (void) FormatLocaleFile(file,"  Intensity: %s\n",CommandOptionToMnemonic(
+    MagickPixelIntensityOptions,(ssize_t) image->intensity));
   (void) FormatLocaleFile(file,"  Compose: %s\n",CommandOptionToMnemonic(
     MagickComposeOptions,(ssize_t) image->compose));
   if ((image->page.width != 0) || (image->page.height != 0) ||
@@ -748,6 +1100,9 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
   if (image->iterations != 1)
     (void) FormatLocaleFile(file,"  Iterations: %.20g\n",(double)
       image->iterations);
+  if (image->duration != 0)
+    (void) FormatLocaleFile(file,"  Duration: %.20g\n",(double)
+      image->duration);
   if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
     (void) FormatLocaleFile(file,"  Scene: %.20g of %.20g\n",(double)
       image->scene,(double) GetImageListLength(image));
@@ -817,6 +1172,9 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
       image_info=DestroyImageInfo(image_info);
     }
   (void) GetImageProperty(image,"exif:*",exception);
+  (void) GetImageProperty(image,"icc:*",exception);
+  (void) GetImageProperty(image,"iptc:*",exception);
+  (void) GetImageProperty(image,"xmp:*",exception);
   ResetImagePropertyIterator(image);
   property=GetNextImageProperty(image);
   if (property != (const char *) NULL)
@@ -864,45 +1222,6 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
           continue;
         (void) FormatLocaleFile(file,"    Profile-%s: %.20g bytes\n",name,
           (double) GetStringInfoLength(profile));
-#if defined(MAGICKCORE_LCMS_DELEGATE)
-        if ((LocaleCompare(name,"icc") == 0) ||
-            (LocaleCompare(name,"icm") == 0))
-          {
-            cmsHPROFILE
-              icc_profile;
-
-            icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
-              (cmsUInt32Number) GetStringInfoLength(profile));
-            if (icc_profile != (cmsHPROFILE *) NULL)
-              {
-#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
-                const char
-                  *name;
-
-                name=cmsTakeProductName(icc_profile);
-                if (name != (const char *) NULL)
-                  (void) FormatLocaleFile(file,"      %s\n",name);
-#else
-                char
-                  info[MaxTextExtent];
-
-                (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoDescription,
-                  "en","US",info,MaxTextExtent);
-                (void) FormatLocaleFile(file,"      Description: %s\n",info);
-                (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoManufacturer,
-                  "en","US",info,MaxTextExtent);
-                (void) FormatLocaleFile(file,"      Manufacturer: %s\n",info);
-                (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoModel,"en",
-                  "US",info,MaxTextExtent);
-                (void) FormatLocaleFile(file,"      Model: %s\n",info);
-                (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoCopyright,
-                  "en","US",info,MaxTextExtent);
-                (void) FormatLocaleFile(file,"      Copyright: %s\n",info);
-#endif
-                (void) cmsCloseProfile(icc_profile);
-              }
-          }
-#endif
         if (LocaleCompare(name,"iptc") == 0)
           {
             char
@@ -1063,7 +1382,9 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
   (void) FormatMagickSize(GetBlobSize(image),MagickFalse,format);
   (void) FormatLocaleFile(file,"  Filesize: %s\n",format);
   (void) FormatMagickSize((MagickSizeType) image->columns*image->rows,
-     MagickFalse,format);
+    MagickFalse,format);
+  if (strlen(format) > 1)
+    format[strlen(format)-1]='\0';
   (void) FormatLocaleFile(file,"  Number pixels: %s\n",format);
   (void) FormatMagickSize((MagickSizeType) ((double) image->columns*image->rows/
     elapsed_time+0.5),MagickFalse,format);