Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %           IIIII  DDDD   EEEEE  N   N  TTTTT  IIIII  FFFFF  Y   Y            %
      7 %             I    D   D  E      NN  N    T      I    F       Y Y             %
      8 %             I    D   D  EEE    N N N    T      I    FFF      Y              %
      9 %             I    D   D  E      N  NN    T      I    F        Y              %
     10 %           IIIII  DDDD   EEEEE  N   N    T    IIIII  F        Y              %
     11 %                                                                             %
     12 %                                                                             %
     13 %               Identify an Image Format and Characteristics.                 %
     14 %                                                                             %
     15 %                           Software Design                                   %
     16 %                                Cristy                                       %
     17 %                            September 1994                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 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 %  Identify describes the format and characteristics of one or more image
     37 %  files.  It will also report if an image is incomplete or corrupt.
     38 %
     39 %
     40 */
     41 
     42 /*
     44   Include declarations.
     45 */
     46 #include "MagickCore/studio.h"
     47 #include "MagickCore/annotate.h"
     48 #include "MagickCore/artifact.h"
     49 #include "MagickCore/attribute.h"
     50 #include "MagickCore/blob.h"
     51 #include "MagickCore/cache.h"
     52 #include "MagickCore/client.h"
     53 #include "MagickCore/coder.h"
     54 #include "MagickCore/color.h"
     55 #include "MagickCore/configure.h"
     56 #include "MagickCore/constitute.h"
     57 #include "MagickCore/decorate.h"
     58 #include "MagickCore/delegate.h"
     59 #include "MagickCore/draw.h"
     60 #include "MagickCore/effect.h"
     61 #include "MagickCore/exception.h"
     62 #include "MagickCore/exception-private.h"
     63 #include "MagickCore/feature.h"
     64 #include "MagickCore/gem.h"
     65 #include "MagickCore/geometry.h"
     66 #include "MagickCore/histogram.h"
     67 #include "MagickCore/identify.h"
     68 #include "MagickCore/image.h"
     69 #include "MagickCore/image-private.h"
     70 #include "MagickCore/list.h"
     71 #include "MagickCore/locale_.h"
     72 #include "MagickCore/log.h"
     73 #include "MagickCore/magic.h"
     74 #include "MagickCore/magick.h"
     75 #include "MagickCore/memory_.h"
     76 #include "MagickCore/module.h"
     77 #include "MagickCore/monitor.h"
     78 #include "MagickCore/montage.h"
     79 #include "MagickCore/option.h"
     80 #include "MagickCore/pixel-accessor.h"
     81 #include "MagickCore/prepress.h"
     82 #include "MagickCore/profile.h"
     83 #include "MagickCore/property.h"
     84 #include "MagickCore/quantize.h"
     85 #include "MagickCore/quantum.h"
     86 #include "MagickCore/random_.h"
     87 #include "MagickCore/registry.h"
     88 #include "MagickCore/resize.h"
     89 #include "MagickCore/resource_.h"
     90 #include "MagickCore/signature.h"
     91 #include "MagickCore/statistic.h"
     92 #include "MagickCore/string_.h"
     93 #include "MagickCore/string-private.h"
     94 #include "MagickCore/timer.h"
     95 #include "MagickCore/token.h"
     96 #include "MagickCore/utility.h"
     97 #include "MagickCore/utility-private.h"
     98 #include "MagickCore/version.h"
     99 
    100 /*
    102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    103 %                                                                             %
    104 %                                                                             %
    105 %                                                                             %
    106 %   I d e n t i f y I m a g e                                                 %
    107 %                                                                             %
    108 %                                                                             %
    109 %                                                                             %
    110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    111 %
    112 %  IdentifyImage() identifies an image by printing its attributes to the file.
    113 %  Attributes include the image width, height, size, and others.
    114 %
    115 %  The format of the IdentifyImage method is:
    116 %
    117 %      MagickBooleanType IdentifyImage(Image *image,FILE *file,
    118 %        const MagickBooleanType verbose,ExceptionInfo *exception)
    119 %
    120 %  A description of each parameter follows:
    121 %
    122 %    o image: the image.
    123 %
    124 %    o file: the file, typically stdout.
    125 %
    126 %    o verbose: A value other than zero prints more detailed information
    127 %      about the image.
    128 %
    129 %    o exception: return any errors or warnings in this structure.
    130 %
    131 */
    132 
    133 static ChannelStatistics *GetLocationStatistics(const Image *image,
    134   const StatisticType type,ExceptionInfo *exception)
    135 {
    136   ChannelStatistics
    137     *channel_statistics;
    138 
    139   register ssize_t
    140     i;
    141 
    142   ssize_t
    143     y;
    144 
    145   assert(image != (Image *) NULL);
    146   assert(image->signature == MagickCoreSignature);
    147   if (image->debug != MagickFalse)
    148     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    149   channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
    150     MaxPixelChannels+1,sizeof(*channel_statistics));
    151   if (channel_statistics == (ChannelStatistics *) NULL)
    152     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    153   (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
    154     sizeof(*channel_statistics));
    155   for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
    156   {
    157     switch (type)
    158     {
    159       case MaximumStatistic:
    160       default:
    161       {
    162         channel_statistics[i].maxima=(-MagickMaximumValue);
    163         break;
    164       }
    165       case MinimumStatistic:
    166       {
    167         channel_statistics[i].minima=MagickMaximumValue;
    168         break;
    169       }
    170     }
    171   }
    172   for (y=0; y < (ssize_t) image->rows; y++)
    173   {
    174     register const Quantum
    175       *magick_restrict p;
    176 
    177     register ssize_t
    178       x;
    179 
    180     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    181     if (p == (const Quantum *) NULL)
    182       break;
    183     for (x=0; x < (ssize_t) image->columns; x++)
    184     {
    185       register ssize_t
    186         i;
    187 
    188       if (GetPixelReadMask(image,p) == 0)
    189         {
    190           p+=GetPixelChannels(image);
    191           continue;
    192         }
    193       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    194       {
    195         PixelChannel channel=GetPixelChannelChannel(image,i);
    196         PixelTrait traits=GetPixelChannelTraits(image,channel);
    197         if (traits == UndefinedPixelTrait)
    198           continue;
    199         switch (type)
    200         {
    201           case MaximumStatistic:
    202           default:
    203           {
    204             if ((double) p[i] > channel_statistics[channel].maxima)
    205               channel_statistics[channel].maxima=(double) p[i];
    206             break;
    207           }
    208           case MinimumStatistic:
    209           {
    210             if ((double) p[i] < channel_statistics[channel].minima)
    211               channel_statistics[channel].minima=(double) p[i];
    212             break;
    213           }
    214         }
    215       }
    216       p+=GetPixelChannels(image);
    217     }
    218   }
    219   return(channel_statistics);
    220 }
    221 
    222 static ssize_t PrintChannelFeatures(FILE *file,const PixelChannel channel,
    223   const char *name,const ChannelFeatures *channel_features)
    224 {
    225 #define PrintFeature(feature) \
    226   GetMagickPrecision(),(feature)[0], \
    227   GetMagickPrecision(),(feature)[1], \
    228   GetMagickPrecision(),(feature)[2], \
    229   GetMagickPrecision(),(feature)[3], \
    230   GetMagickPrecision(),((feature)[0]+(feature)[1]+(feature)[2]+(feature)[3])/4.0 \
    231 
    232 #define FeaturesFormat "    %s:\n" \
    233   "      Angular Second Moment:\n" \
    234   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    235   "      Contrast:\n" \
    236   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    237   "      Correlation:\n" \
    238   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    239   "      Sum of Squares Variance:\n" \
    240   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    241   "      Inverse Difference Moment:\n" \
    242   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    243   "      Sum Average:\n" \
    244   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    245   "      Sum Variance:\n" \
    246   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    247   "      Sum Entropy:\n" \
    248   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    249   "      Entropy:\n" \
    250   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    251   "      Difference Variance:\n" \
    252   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    253   "      Difference Entropy:\n" \
    254   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    255   "      Information Measure of Correlation 1:\n" \
    256   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    257   "      Information Measure of Correlation 2:\n" \
    258   "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
    259   "      Maximum Correlation Coefficient:\n" \
    260   "        %.*g, %.*g, %.*g, %.*g, %.*g\n"
    261 
    262   ssize_t
    263     n;
    264 
    265   n=FormatLocaleFile(file,FeaturesFormat,name,
    266     PrintFeature(channel_features[channel].angular_second_moment),
    267     PrintFeature(channel_features[channel].contrast),
    268     PrintFeature(channel_features[channel].correlation),
    269     PrintFeature(channel_features[channel].variance_sum_of_squares),
    270     PrintFeature(channel_features[channel].inverse_difference_moment),
    271     PrintFeature(channel_features[channel].sum_average),
    272     PrintFeature(channel_features[channel].sum_variance),
    273     PrintFeature(channel_features[channel].sum_entropy),
    274     PrintFeature(channel_features[channel].entropy),
    275     PrintFeature(channel_features[channel].difference_variance),
    276     PrintFeature(channel_features[channel].difference_entropy),
    277     PrintFeature(channel_features[channel].measure_of_correlation_1),
    278     PrintFeature(channel_features[channel].measure_of_correlation_2),
    279     PrintFeature(channel_features[channel].maximum_correlation_coefficient));
    280   return(n);
    281 }
    282 
    283 static ssize_t PrintChannelLocations(FILE *file,const Image *image,
    284   const PixelChannel channel,const char *name,const StatisticType type,
    285   const size_t max_locations,const ChannelStatistics *channel_statistics)
    286 {
    287   double
    288     target;
    289 
    290   ExceptionInfo
    291     *exception;
    292 
    293   ssize_t
    294     n,
    295     y;
    296 
    297   switch (type)
    298   {
    299     case MaximumStatistic:
    300     default:
    301     {
    302       target=channel_statistics[channel].maxima;
    303       break;
    304     }
    305     case MinimumStatistic:
    306     {
    307       target=channel_statistics[channel].minima;
    308       break;
    309     }
    310   }
    311   (void) FormatLocaleFile(file,"  %s: %.*g (%.*g)",name,GetMagickPrecision(),
    312     target,GetMagickPrecision(),QuantumScale*target);
    313   exception=AcquireExceptionInfo();
    314   n=0;
    315   for (y=0; y < (ssize_t) image->rows; y++)
    316   {
    317     register const Quantum
    318       *p;
    319 
    320     ssize_t
    321       offset,
    322       x;
    323 
    324     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    325     if (p == (const Quantum *) NULL)
    326       break;
    327     for (x=0; x < (ssize_t) image->columns; x++)
    328     {
    329       MagickBooleanType
    330         match;
    331 
    332       PixelTrait traits=GetPixelChannelTraits(image,channel);
    333       if (traits == UndefinedPixelTrait)
    334         continue;
    335       offset=GetPixelChannelOffset(image,channel);
    336       match=fabs((double) (p[offset]-target)) < 0.5 ? MagickTrue : MagickFalse;
    337       if (match != MagickFalse)
    338         {
    339           if ((max_locations != 0) && (n >= (ssize_t) max_locations))
    340             break;
    341           (void) FormatLocaleFile(file," %.20g,%.20g",(double) x,(double) y);
    342           n++;
    343         }
    344       p+=GetPixelChannels(image);
    345     }
    346     if (x < (ssize_t) image->columns)
    347       break;
    348   }
    349   (void) FormatLocaleFile(file,"\n");
    350   return(n);
    351 }
    352 
    353 static ssize_t PrintChannelMoments(FILE *file,const PixelChannel channel,
    354   const char *name,const double scale,const ChannelMoments *channel_moments)
    355 {
    356   double
    357     powers[MaximumNumberOfImageMoments] =
    358       { 1.0, 2.0, 3.0, 3.0, 6.0, 4.0, 6.0, 4.0 };
    359 
    360   register ssize_t
    361     i;
    362 
    363   ssize_t
    364     n;
    365 
    366   n=FormatLocaleFile(file,"    %s:\n",name);
    367   n+=FormatLocaleFile(file,"      Centroid: %.*g,%.*g\n",
    368     GetMagickPrecision(),channel_moments[channel].centroid.x,
    369     GetMagickPrecision(),channel_moments[channel].centroid.y);
    370   n+=FormatLocaleFile(file,"      Ellipse Semi-Major/Minor axis: %.*g,%.*g\n",
    371     GetMagickPrecision(),channel_moments[channel].ellipse_axis.x,
    372     GetMagickPrecision(),channel_moments[channel].ellipse_axis.y);
    373   n+=FormatLocaleFile(file,"      Ellipse angle: %.*g\n",
    374     GetMagickPrecision(),channel_moments[channel].ellipse_angle);
    375   n+=FormatLocaleFile(file,"      Ellipse eccentricity: %.*g\n",
    376     GetMagickPrecision(),channel_moments[channel].ellipse_eccentricity);
    377   n+=FormatLocaleFile(file,"      Ellipse intensity: %.*g (%.*g)\n",
    378     GetMagickPrecision(),pow(scale,powers[0])*
    379     channel_moments[channel].ellipse_intensity,GetMagickPrecision(),
    380     channel_moments[channel].ellipse_intensity);
    381   for (i=0; i < MaximumNumberOfImageMoments; i++)
    382     n+=FormatLocaleFile(file,"      I%.20g: %.*g (%.*g)\n",i+1.0,
    383       GetMagickPrecision(),channel_moments[channel].invariant[i]/pow(scale,
    384       powers[i]),GetMagickPrecision(),channel_moments[channel].invariant[i]);
    385   return(n);
    386 }
    387 
    388 static ssize_t PrintChannelPerceptualHash(FILE *file,const PixelChannel channel,
    389   const char *name,const ChannelPerceptualHash *channel_phash)
    390 {
    391   register ssize_t
    392     i;
    393 
    394   ssize_t
    395     n;
    396 
    397   n=FormatLocaleFile(file,"    %s:\n",name);
    398   for (i=0; i < MaximumNumberOfPerceptualHashes; i++)
    399     n+=FormatLocaleFile(file,"      PH%.20g: %.*g, %.*g\n",i+1.0,
    400       GetMagickPrecision(),channel_phash[channel].srgb_hu_phash[i],
    401       GetMagickPrecision(),channel_phash[channel].hclp_hu_phash[i]);
    402   return(n);
    403 }
    404 
    405 static ssize_t PrintChannelStatistics(FILE *file,const PixelChannel channel,
    406   const char *name,const double scale,
    407   const ChannelStatistics *channel_statistics)
    408 {
    409 #define StatisticsFormat "    %s:\n      min: " QuantumFormat  \
    410   " (%g)\n      max: " QuantumFormat " (%g)\n"  \
    411   "      mean: %g (%g)\n      standard deviation: %g (%g)\n"  \
    412   "      kurtosis: %g\n      skewness: %g\n      entropy: %g\n"
    413 
    414   ssize_t
    415     n;
    416 
    417   n=FormatLocaleFile(file,StatisticsFormat,name,ClampToQuantum((MagickRealType)
    418     (scale*channel_statistics[channel].minima)),
    419     channel_statistics[channel].minima/(double) QuantumRange,ClampToQuantum(
    420     (MagickRealType) (scale*channel_statistics[channel].maxima)),
    421     channel_statistics[channel].maxima/(double) QuantumRange,scale*
    422     channel_statistics[channel].mean,channel_statistics[channel].mean/(double)
    423     QuantumRange,scale*channel_statistics[channel].standard_deviation,
    424     channel_statistics[channel].standard_deviation/(double) QuantumRange,
    425     channel_statistics[channel].kurtosis,channel_statistics[channel].skewness,
    426     channel_statistics[channel].entropy);
    427   return(n);
    428 }
    429 
    430 MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
    431   const MagickBooleanType verbose,ExceptionInfo *exception)
    432 {
    433   char
    434     color[MagickPathExtent],
    435     format[MagickPathExtent],
    436     key[MagickPathExtent];
    437 
    438   ChannelFeatures
    439     *channel_features;
    440 
    441   ChannelMoments
    442     *channel_moments;
    443 
    444   ChannelPerceptualHash
    445     *channel_phash;
    446 
    447   ChannelStatistics
    448     *channel_statistics;
    449 
    450   ColorspaceType
    451     colorspace;
    452 
    453   const char
    454     *artifact,
    455     *locate,
    456     *name,
    457     *property,
    458     *registry,
    459     *value;
    460 
    461   const MagickInfo
    462     *magick_info;
    463 
    464   double
    465     elapsed_time,
    466     scale,
    467     user_time;
    468 
    469   ImageType
    470     base_type,
    471     type;
    472 
    473   MagickBooleanType
    474     ping;
    475 
    476   register const Quantum
    477     *p;
    478 
    479   register ssize_t
    480     i,
    481     x;
    482 
    483   size_t
    484     distance;
    485 
    486   ssize_t
    487     y;
    488 
    489   assert(image != (Image *) NULL);
    490   assert(image->signature == MagickCoreSignature);
    491   if (image->debug != MagickFalse)
    492     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    493   if (file == (FILE *) NULL)
    494     file=stdout;
    495   colorspace=image->colorspace;
    496   type=IdentifyImageType(image,exception);
    497   if ((type == BilevelType) || (type == GrayscaleType) ||
    498       (type == GrayscaleAlphaType))
    499     colorspace=GRAYColorspace;
    500   locate=GetImageArtifact(image,"identify:locate");
    501   if (locate != (const char *) NULL)
    502     {
    503       const char
    504         *limit;
    505 
    506       size_t
    507         max_locations;
    508 
    509       StatisticType
    510         type;
    511 
    512       /*
    513         Display minimum, maximum, or mean pixel locations.
    514       */
    515       type=(StatisticType) ParseCommandOption(MagickStatisticOptions,
    516         MagickFalse,locate);
    517       limit=GetImageArtifact(image,"identify:limit");
    518       max_locations=0;
    519       if (limit != (const char *) NULL)
    520         max_locations=StringToUnsignedLong(limit);
    521       channel_statistics=GetLocationStatistics(image,type,exception);
    522       if (channel_statistics == (ChannelStatistics *) NULL)
    523         return(MagickFalse);
    524       (void) FormatLocaleFile(file,"Channel %s locations:\n",locate);
    525       switch (colorspace)
    526       {
    527         case RGBColorspace:
    528         default:
    529         {
    530           (void) PrintChannelLocations(file,image,RedPixelChannel,"Red",
    531             type,max_locations,channel_statistics);
    532           (void) PrintChannelLocations(file,image,GreenPixelChannel,"Green",
    533             type,max_locations,channel_statistics);
    534           (void) PrintChannelLocations(file,image,BluePixelChannel,"Blue",
    535             type,max_locations,channel_statistics);
    536           break;
    537         }
    538         case CMYKColorspace:
    539         {
    540           (void) PrintChannelLocations(file,image,CyanPixelChannel,"Cyan",
    541             type,max_locations,channel_statistics);
    542           (void) PrintChannelLocations(file,image,MagentaPixelChannel,"Magenta",
    543             type,max_locations,channel_statistics);
    544           (void) PrintChannelLocations(file,image,YellowPixelChannel,"Yellow",
    545             type,max_locations,channel_statistics);
    546           (void) PrintChannelLocations(file,image,BlackPixelChannel,"Black",
    547             type,max_locations,channel_statistics);
    548           break;
    549         }
    550         case GRAYColorspace:
    551         {
    552           (void) PrintChannelLocations(file,image,GrayPixelChannel,"Gray",
    553             type,max_locations,channel_statistics);
    554           break;
    555         }
    556       }
    557       if (image->alpha_trait != UndefinedPixelTrait)
    558         (void) PrintChannelLocations(file,image,AlphaPixelChannel,"Alpha",
    559           type,max_locations,channel_statistics);
    560       channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
    561         channel_statistics);
    562       return(ferror(file) != 0 ? MagickFalse : MagickTrue);
    563     }
    564   *format='\0';
    565   elapsed_time=GetElapsedTime(&image->timer);
    566   user_time=GetUserTime(&image->timer);
    567   GetTimerInfo(&image->timer);
    568   if (verbose == MagickFalse)
    569     {
    570       /*
    571         Display summary info about the image.
    572       */
    573       if (*image->magick_filename != '\0')
    574         if (LocaleCompare(image->magick_filename,image->filename) != 0)
    575           (void) FormatLocaleFile(file,"%s=>",image->magick_filename);
    576        if ((GetPreviousImageInList(image) == (Image *) NULL) &&
    577            (GetNextImageInList(image) == (Image *) NULL) &&
    578            (image->scene == 0))
    579         (void) FormatLocaleFile(file,"%s ",image->filename);
    580       else
    581         (void) FormatLocaleFile(file,"%s[%.20g] ",image->filename,(double)
    582           image->scene);
    583       (void) FormatLocaleFile(file,"%s ",image->magick);
    584       if ((image->magick_columns != 0) || (image->magick_rows != 0))
    585         if ((image->magick_columns != image->columns) ||
    586             (image->magick_rows != image->rows))
    587           (void) FormatLocaleFile(file,"%.20gx%.20g=>",(double)
    588             image->magick_columns,(double) image->magick_rows);
    589       (void) FormatLocaleFile(file,"%.20gx%.20g ",(double) image->columns,
    590         (double) image->rows);
    591       if ((image->page.width != 0) || (image->page.height != 0) ||
    592           (image->page.x != 0) || (image->page.y != 0))
    593         (void) FormatLocaleFile(file,"%.20gx%.20g%+.20g%+.20g ",(double)
    594           image->page.width,(double) image->page.height,(double) image->page.x,
    595           (double) image->page.y);
    596       (void) FormatLocaleFile(file,"%.20g-bit ",(double) image->depth);
    597       if (image->type != UndefinedType)
    598         (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic(
    599           MagickTypeOptions,(ssize_t) image->type));
    600       if (image->colorspace != UndefinedColorspace)
    601         (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic(
    602           MagickColorspaceOptions,(ssize_t) image->colorspace));
    603       if (image->storage_class == DirectClass)
    604         {
    605           if (image->total_colors != 0)
    606             {
    607               (void) FormatMagickSize(image->total_colors,MagickFalse,"B",
    608                 MagickPathExtent,format);
    609               (void) FormatLocaleFile(file,"%s ",format);
    610             }
    611         }
    612       else
    613         if (image->total_colors <= image->colors)
    614           (void) FormatLocaleFile(file,"%.20gc ",(double)
    615             image->colors);
    616         else
    617           (void) FormatLocaleFile(file,"%.20g=>%.20gc ",(double)
    618             image->total_colors,(double) image->colors);
    619       if (image->error.mean_error_per_pixel != 0.0)
    620         (void) FormatLocaleFile(file,"%.20g/%f/%fdb ",(double)
    621           (image->error.mean_error_per_pixel+0.5),
    622           image->error.normalized_mean_error,
    623           image->error.normalized_maximum_error);
    624       if (GetBlobSize(image) != 0)
    625         {
    626           (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",
    627             MagickPathExtent,format);
    628           (void) FormatLocaleFile(file,"%s ",format);
    629         }
    630       (void) FormatLocaleFile(file,"%0.3fu %lu:%02lu.%03lu",user_time,
    631         (unsigned long) (elapsed_time/60.0),(unsigned long) floor(fmod(
    632         elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-
    633         floor(elapsed_time))));
    634       (void) FormatLocaleFile(file,"\n");
    635       (void) fflush(file);
    636       return(ferror(file) != 0 ? MagickFalse : MagickTrue);
    637     }
    638   /*
    639     Display verbose info about the image.
    640   */
    641   p=GetVirtualPixels(image,0,0,1,1,exception);
    642   ping=p == (const Quantum *) NULL ? MagickTrue : MagickFalse;
    643   (void) SignatureImage(image,exception);
    644   (void) FormatLocaleFile(file,"Image: %s\n",image->filename);
    645   if (*image->magick_filename != '\0')
    646     if (LocaleCompare(image->magick_filename,image->filename) != 0)
    647       {
    648         char
    649           filename[MagickPathExtent];
    650 
    651         GetPathComponent(image->magick_filename,TailPath,filename);
    652         (void) FormatLocaleFile(file,"  Base filename: %s\n",filename);
    653       }
    654   magick_info=GetMagickInfo(image->magick,exception);
    655   if ((magick_info == (const MagickInfo *) NULL) ||
    656       (GetMagickDescription(magick_info) == (const char *) NULL))
    657     (void) FormatLocaleFile(file,"  Format: %s\n",image->magick);
    658   else
    659     (void) FormatLocaleFile(file,"  Format: %s (%s)\n",image->magick,
    660       GetMagickDescription(magick_info));
    661   if ((magick_info != (const MagickInfo *) NULL) &&
    662       (GetMagickMimeType(magick_info) != (const char *) NULL))
    663     (void) FormatLocaleFile(file,"  Mime type: %s\n",GetMagickMimeType(
    664       magick_info));
    665   (void) FormatLocaleFile(file,"  Class: %s\n",CommandOptionToMnemonic(
    666     MagickClassOptions,(ssize_t) image->storage_class));
    667   (void) FormatLocaleFile(file,"  Geometry: %.20gx%.20g%+.20g%+.20g\n",(double)
    668     image->columns,(double) image->rows,(double) image->tile_offset.x,(double)
    669     image->tile_offset.y);
    670   if ((image->magick_columns != 0) || (image->magick_rows != 0))
    671     if ((image->magick_columns != image->columns) ||
    672         (image->magick_rows != image->rows))
    673       (void) FormatLocaleFile(file,"  Base geometry: %.20gx%.20g\n",(double)
    674         image->magick_columns,(double) image->magick_rows);
    675   if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
    676     {
    677       (void) FormatLocaleFile(file,"  Resolution: %gx%g\n",image->resolution.x,
    678         image->resolution.y);
    679       (void) FormatLocaleFile(file,"  Print size: %gx%g\n",(double)
    680         image->columns/image->resolution.x,(double) image->rows/
    681         image->resolution.y);
    682     }
    683   (void) FormatLocaleFile(file,"  Units: %s\n",CommandOptionToMnemonic(
    684     MagickResolutionOptions,(ssize_t) image->units));
    685   (void) FormatLocaleFile(file,"  Type: %s\n",CommandOptionToMnemonic(
    686     MagickTypeOptions,(ssize_t) type));
    687   base_type=GetImageType(image);
    688   if (type != base_type)
    689     (void) FormatLocaleFile(file,"  Base type: %s\n",CommandOptionToMnemonic(
    690       MagickTypeOptions,(ssize_t) base_type));
    691   (void) FormatLocaleFile(file,"  Endianess: %s\n",CommandOptionToMnemonic(
    692     MagickEndianOptions,(ssize_t) image->endian));
    693   /*
    694     Detail channel depth and extrema.
    695   */
    696   (void) FormatLocaleFile(file,"  Colorspace: %s\n",CommandOptionToMnemonic(
    697     MagickColorspaceOptions,(ssize_t) image->colorspace));
    698   channel_statistics=(ChannelStatistics *) NULL;
    699   channel_moments=(ChannelMoments *) NULL;
    700   channel_phash=(ChannelPerceptualHash *) NULL;
    701   channel_features=(ChannelFeatures *) NULL;
    702   scale=1.0;
    703   if (ping == MagickFalse)
    704     {
    705       size_t
    706         depth;
    707 
    708       channel_statistics=GetImageStatistics(image,exception);
    709       if (channel_statistics == (ChannelStatistics *) NULL)
    710         return(MagickFalse);
    711       artifact=GetImageArtifact(image,"identify:moments");
    712       if (artifact != (const char *) NULL)
    713         {
    714           channel_moments=GetImageMoments(image,exception);
    715           channel_phash=GetImagePerceptualHash(image,exception);
    716         }
    717       artifact=GetImageArtifact(image,"identify:features");
    718       if (artifact != (const char *) NULL)
    719         {
    720           distance=StringToUnsignedLong(artifact);
    721           channel_features=GetImageFeatures(image,distance,exception);
    722         }
    723       depth=GetImageDepth(image,exception);
    724       if (image->depth == depth)
    725         (void) FormatLocaleFile(file,"  Depth: %.20g-bit\n",(double)
    726           image->depth);
    727       else
    728         (void) FormatLocaleFile(file,"  Depth: %.20g/%.20g-bit\n",(double)
    729           image->depth,(double) depth);
    730       (void) FormatLocaleFile(file,"  Channel depth:\n");
    731       switch (colorspace)
    732       {
    733         case RGBColorspace:
    734         default:
    735         {
    736           (void) FormatLocaleFile(file,"    Red: %.20g-bit\n",(double)
    737             channel_statistics[RedPixelChannel].depth);
    738           (void) FormatLocaleFile(file,"    Green: %.20g-bit\n",(double)
    739             channel_statistics[GreenPixelChannel].depth);
    740           (void) FormatLocaleFile(file,"    Blue: %.20g-bit\n",(double)
    741             channel_statistics[BluePixelChannel].depth);
    742           break;
    743         }
    744         case CMYKColorspace:
    745         {
    746           (void) FormatLocaleFile(file,"    Cyan: %.20g-bit\n",(double)
    747             channel_statistics[CyanPixelChannel].depth);
    748           (void) FormatLocaleFile(file,"    Magenta: %.20g-bit\n",(double)
    749             channel_statistics[MagentaPixelChannel].depth);
    750           (void) FormatLocaleFile(file,"    Yellow: %.20g-bit\n",(double)
    751             channel_statistics[YellowPixelChannel].depth);
    752           (void) FormatLocaleFile(file,"    Black: %.20g-bit\n",(double)
    753             channel_statistics[BlackPixelChannel].depth);
    754           break;
    755         }
    756         case GRAYColorspace:
    757         {
    758           (void) FormatLocaleFile(file,"    Gray: %.20g-bit\n",(double)
    759             channel_statistics[GrayPixelChannel].depth);
    760           break;
    761         }
    762       }
    763       if (image->alpha_trait != UndefinedPixelTrait)
    764         (void) FormatLocaleFile(file,"    Alpha: %.20g-bit\n",(double)
    765           channel_statistics[AlphaPixelChannel].depth);
    766       scale=1.0;
    767       if (image->depth <= MAGICKCORE_QUANTUM_DEPTH)
    768         scale=(double) QuantumRange/((size_t) QuantumRange >> ((size_t)
    769           MAGICKCORE_QUANTUM_DEPTH-image->depth));
    770     }
    771   if (channel_statistics != (ChannelStatistics *) NULL)
    772     {
    773       (void) FormatLocaleFile(file,"  Channel statistics:\n");
    774       (void) FormatLocaleFile(file,"    Pixels: %.20g\n",(double)
    775         image->columns*image->rows);
    776       switch (colorspace)
    777       {
    778         case RGBColorspace:
    779         default:
    780         {
    781           (void) PrintChannelStatistics(file,RedPixelChannel,"Red",1.0/
    782             scale,channel_statistics);
    783           (void) PrintChannelStatistics(file,GreenPixelChannel,"Green",1.0/
    784             scale,channel_statistics);
    785           (void) PrintChannelStatistics(file,BluePixelChannel,"Blue",1.0/
    786             scale,channel_statistics);
    787           break;
    788         }
    789         case CMYKColorspace:
    790         {
    791           (void) PrintChannelStatistics(file,CyanPixelChannel,"Cyan",1.0/
    792             scale,channel_statistics);
    793           (void) PrintChannelStatistics(file,MagentaPixelChannel,"Magenta",1.0/
    794             scale,channel_statistics);
    795           (void) PrintChannelStatistics(file,YellowPixelChannel,"Yellow",1.0/
    796             scale,channel_statistics);
    797           (void) PrintChannelStatistics(file,BlackPixelChannel,"Black",1.0/
    798             scale,channel_statistics);
    799           break;
    800         }
    801         case GRAYColorspace:
    802         {
    803           (void) PrintChannelStatistics(file,GrayPixelChannel,"Gray",1.0/
    804             scale,channel_statistics);
    805           break;
    806         }
    807       }
    808       if (image->alpha_trait != UndefinedPixelTrait)
    809         (void) PrintChannelStatistics(file,AlphaPixelChannel,"Alpha",1.0/
    810           scale,channel_statistics);
    811       if (colorspace != GRAYColorspace)
    812         {
    813           (void) FormatLocaleFile(file,"  Image statistics:\n");
    814           (void) PrintChannelStatistics(file,(PixelChannel) MaxPixelChannels,
    815             "Overall",1.0/scale,channel_statistics);
    816         }
    817       channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
    818         channel_statistics);
    819     }
    820   if (channel_moments != (ChannelMoments *) NULL)
    821     {
    822       scale=(double) ((1UL << image->depth)-1);
    823       (void) FormatLocaleFile(file,"  Channel moments:\n");
    824       switch (colorspace)
    825       {
    826         case RGBColorspace:
    827         default:
    828         {
    829           (void) PrintChannelMoments(file,RedPixelChannel,"Red",scale,
    830             channel_moments);
    831           (void) PrintChannelMoments(file,GreenPixelChannel,"Green",scale,
    832             channel_moments);
    833           (void) PrintChannelMoments(file,BluePixelChannel,"Blue",scale,
    834             channel_moments);
    835           break;
    836         }
    837         case CMYKColorspace:
    838         {
    839           (void) PrintChannelMoments(file,CyanPixelChannel,"Cyan",scale,
    840             channel_moments);
    841           (void) PrintChannelMoments(file,MagentaPixelChannel,"Magenta",scale,
    842             channel_moments);
    843           (void) PrintChannelMoments(file,YellowPixelChannel,"Yellow",scale,
    844             channel_moments);
    845           (void) PrintChannelMoments(file,BlackPixelChannel,"Black",scale,
    846             channel_moments);
    847           break;
    848         }
    849         case GRAYColorspace:
    850         {
    851           (void) PrintChannelMoments(file,GrayPixelChannel,"Gray",scale,
    852             channel_moments);
    853           break;
    854         }
    855       }
    856       if (image->alpha_trait != UndefinedPixelTrait)
    857         (void) PrintChannelMoments(file,AlphaPixelChannel,"Alpha",scale,
    858           channel_moments);
    859       if (colorspace != GRAYColorspace)
    860         {
    861           (void) FormatLocaleFile(file,"  Image moments:\n");
    862           (void) PrintChannelMoments(file,(PixelChannel) MaxPixelChannels,
    863             "Overall",scale,channel_moments);
    864         }
    865       channel_moments=(ChannelMoments *) RelinquishMagickMemory(
    866         channel_moments);
    867     }
    868   if (channel_phash != (ChannelPerceptualHash *) NULL)
    869     {
    870       (void) FormatLocaleFile(file,"  Channel perceptual hash:\n");
    871       (void) PrintChannelPerceptualHash(file,RedPixelChannel,"Red, Hue",
    872         channel_phash);
    873       (void) PrintChannelPerceptualHash(file,GreenPixelChannel,"Green, Chroma",
    874         channel_phash);
    875       (void) PrintChannelPerceptualHash(file,BluePixelChannel,"Blue, Luma",
    876         channel_phash);
    877       if (image->alpha_trait != UndefinedPixelTrait)
    878         (void) PrintChannelPerceptualHash(file,AlphaPixelChannel,"Alpha, Alpha",
    879           channel_phash);
    880       channel_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(
    881         channel_phash);
    882     }
    883   if (channel_features != (ChannelFeatures *) NULL)
    884     {
    885       (void) FormatLocaleFile(file,"  Channel features (horizontal, vertical, "
    886         "left and right diagonals, average):\n");
    887       switch (colorspace)
    888       {
    889         case RGBColorspace:
    890         default:
    891         {
    892           (void) PrintChannelFeatures(file,RedPixelChannel,"Red",
    893             channel_features);
    894           (void) PrintChannelFeatures(file,GreenPixelChannel,"Green",
    895             channel_features);
    896           (void) PrintChannelFeatures(file,BluePixelChannel,"Blue",
    897             channel_features);
    898           break;
    899         }
    900         case CMYKColorspace:
    901         {
    902           (void) PrintChannelFeatures(file,CyanPixelChannel,"Cyan",
    903             channel_features);
    904           (void) PrintChannelFeatures(file,MagentaPixelChannel,"Magenta",
    905             channel_features);
    906           (void) PrintChannelFeatures(file,YellowPixelChannel,"Yellow",
    907             channel_features);
    908           (void) PrintChannelFeatures(file,BlackPixelChannel,"Black",
    909             channel_features);
    910           break;
    911         }
    912         case GRAYColorspace:
    913         {
    914           (void) PrintChannelFeatures(file,GrayPixelChannel,"Gray",
    915             channel_features);
    916           break;
    917         }
    918       }
    919       if (image->alpha_trait != UndefinedPixelTrait)
    920         (void) PrintChannelFeatures(file,AlphaPixelChannel,"Alpha",
    921           channel_features);
    922       channel_features=(ChannelFeatures *) RelinquishMagickMemory(
    923         channel_features);
    924     }
    925   if (ping == MagickFalse)
    926     {
    927       if (image->colorspace == CMYKColorspace)
    928         (void) FormatLocaleFile(file,"  Total ink density: %*g%%\n",
    929           GetMagickPrecision(),100.0*GetImageTotalInkDensity(image,exception)/
    930           (double) QuantumRange);
    931       x=0;
    932       if (image->alpha_trait != UndefinedPixelTrait)
    933         {
    934           register const Quantum
    935             *p;
    936 
    937           p=(const Quantum *) NULL;
    938           for (y=0; y < (ssize_t) image->rows; y++)
    939           {
    940             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    941             if (p == (const Quantum *) NULL)
    942               break;
    943             for (x=0; x < (ssize_t) image->columns; x++)
    944             {
    945               if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)
    946                 break;
    947               p+=GetPixelChannels(image);
    948             }
    949             if (x < (ssize_t) image->columns)
    950               break;
    951           }
    952           if ((x < (ssize_t) image->columns) || (y < (ssize_t) image->rows))
    953             {
    954               char
    955                 tuple[MagickPathExtent];
    956 
    957               PixelInfo
    958                 pixel;
    959 
    960               GetPixelInfo(image,&pixel);
    961               GetPixelInfoPixel(image,p,&pixel);
    962               (void) QueryColorname(image,&pixel,SVGCompliance,tuple,
    963                 exception);
    964               (void) FormatLocaleFile(file,"  Alpha: %s ",tuple);
    965               GetColorTuple(&pixel,MagickTrue,tuple);
    966               (void) FormatLocaleFile(file,"  %s\n",tuple);
    967             }
    968         }
    969       if (IsHistogramImage(image,exception) != MagickFalse)
    970         {
    971           (void) FormatLocaleFile(file,"  Colors: %.20g\n",(double)
    972             GetNumberColors(image,(FILE *) NULL,exception));
    973           (void) FormatLocaleFile(file,"  Histogram:\n");
    974           (void) GetNumberColors(image,file,exception);
    975         }
    976       else
    977         {
    978           artifact=GetImageArtifact(image,"identify:unique-colors");
    979           if (IsStringTrue(artifact) != MagickFalse)
    980             (void) FormatLocaleFile(file,"  Colors: %.20g\n",(double)
    981               GetNumberColors(image,(FILE *) NULL,exception));
    982         }
    983     }
    984   if (image->storage_class == PseudoClass)
    985     {
    986       (void) FormatLocaleFile(file,"  Colormap entries: %.20g\n",(double)
    987         image->colors);
    988       (void) FormatLocaleFile(file,"  Colormap:\n");
    989       if (image->colors <= 1024)
    990         {
    991           char
    992             color[MagickPathExtent],
    993             hex[MagickPathExtent],
    994             tuple[MagickPathExtent];
    995 
    996           PixelInfo
    997             pixel;
    998 
    999           register PixelInfo
   1000             *magick_restrict p;
   1001 
   1002           GetPixelInfo(image,&pixel);
   1003           p=image->colormap;
   1004           for (i=0; i < (ssize_t) image->colors; i++)
   1005           {
   1006             pixel=(*p);
   1007             (void) CopyMagickString(tuple,"(",MagickPathExtent);
   1008             ConcatenateColorComponent(&pixel,RedPixelChannel,X11Compliance,
   1009               tuple);
   1010             (void) ConcatenateMagickString(tuple,",",MagickPathExtent);
   1011             ConcatenateColorComponent(&pixel,GreenPixelChannel,X11Compliance,
   1012               tuple);
   1013             (void) ConcatenateMagickString(tuple,",",MagickPathExtent);
   1014             ConcatenateColorComponent(&pixel,BluePixelChannel,X11Compliance,
   1015               tuple);
   1016             if (pixel.colorspace == CMYKColorspace)
   1017               {
   1018                 (void) ConcatenateMagickString(tuple,",",MagickPathExtent);
   1019                 ConcatenateColorComponent(&pixel,BlackPixelChannel,
   1020                   X11Compliance,tuple);
   1021               }
   1022             if (pixel.alpha_trait != UndefinedPixelTrait)
   1023               {
   1024                 (void) ConcatenateMagickString(tuple,",",MagickPathExtent);
   1025                 ConcatenateColorComponent(&pixel,AlphaPixelChannel,
   1026                   X11Compliance,tuple);
   1027               }
   1028             (void) ConcatenateMagickString(tuple,")",MagickPathExtent);
   1029             (void) QueryColorname(image,&pixel,SVGCompliance,color,
   1030               exception);
   1031             GetColorTuple(&pixel,MagickTrue,hex);
   1032             (void) FormatLocaleFile(file,"  %8ld: %s %s %s\n",(long) i,tuple,
   1033               hex,color);
   1034             p++;
   1035           }
   1036         }
   1037     }
   1038   if (image->error.mean_error_per_pixel != 0.0)
   1039     (void) FormatLocaleFile(file,"  Mean error per pixel: %g\n",
   1040       image->error.mean_error_per_pixel);
   1041   if (image->error.normalized_mean_error != 0.0)
   1042     (void) FormatLocaleFile(file,"  Normalized mean error: %g\n",
   1043       image->error.normalized_mean_error);
   1044   if (image->error.normalized_maximum_error != 0.0)
   1045     (void) FormatLocaleFile(file,"  Normalized maximum error: %g\n",
   1046       image->error.normalized_maximum_error);
   1047   (void) FormatLocaleFile(file,"  Rendering intent: %s\n",
   1048     CommandOptionToMnemonic(MagickIntentOptions,(ssize_t)
   1049     image->rendering_intent));
   1050   if (image->gamma != 0.0)
   1051     (void) FormatLocaleFile(file,"  Gamma: %g\n",image->gamma);
   1052   if ((image->chromaticity.red_primary.x != 0.0) ||
   1053       (image->chromaticity.green_primary.x != 0.0) ||
   1054       (image->chromaticity.blue_primary.x != 0.0) ||
   1055       (image->chromaticity.white_point.x != 0.0))
   1056     {
   1057       /*
   1058         Display image chromaticity.
   1059       */
   1060       (void) FormatLocaleFile(file,"  Chromaticity:\n");
   1061       (void) FormatLocaleFile(file,"    red primary: (%g,%g)\n",
   1062         image->chromaticity.red_primary.x,image->chromaticity.red_primary.y);
   1063       (void) FormatLocaleFile(file,"    green primary: (%g,%g)\n",
   1064         image->chromaticity.green_primary.x,
   1065         image->chromaticity.green_primary.y);
   1066       (void) FormatLocaleFile(file,"    blue primary: (%g,%g)\n",
   1067         image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y);
   1068       (void) FormatLocaleFile(file,"    white point: (%g,%g)\n",
   1069         image->chromaticity.white_point.x,image->chromaticity.white_point.y);
   1070     }
   1071   if ((image->extract_info.width*image->extract_info.height) != 0)
   1072     (void) FormatLocaleFile(file,"  Tile geometry: %.20gx%.20g%+.20g%+.20g\n",
   1073       (double) image->extract_info.width,(double) image->extract_info.height,
   1074       (double) image->extract_info.x,(double) image->extract_info.y);
   1075   (void) QueryColorname(image,&image->alpha_color,SVGCompliance,color,
   1076     exception);
   1077   (void) FormatLocaleFile(file,"  Alpha color: %s\n",color);
   1078   (void) QueryColorname(image,&image->background_color,SVGCompliance,color,
   1079     exception);
   1080   (void) FormatLocaleFile(file,"  Background color: %s\n",color);
   1081   (void) QueryColorname(image,&image->border_color,SVGCompliance,color,
   1082     exception);
   1083   (void) FormatLocaleFile(file,"  Border color: %s\n",color);
   1084   (void) QueryColorname(image,&image->transparent_color,SVGCompliance,color,
   1085     exception);
   1086   (void) FormatLocaleFile(file,"  Transparent color: %s\n",color);
   1087   (void) FormatLocaleFile(file,"  Interlace: %s\n",CommandOptionToMnemonic(
   1088     MagickInterlaceOptions,(ssize_t) image->interlace));
   1089   (void) FormatLocaleFile(file,"  Intensity: %s\n",CommandOptionToMnemonic(
   1090     MagickPixelIntensityOptions,(ssize_t) image->intensity));
   1091   (void) FormatLocaleFile(file,"  Compose: %s\n",CommandOptionToMnemonic(
   1092     MagickComposeOptions,(ssize_t) image->compose));
   1093   if ((image->page.width != 0) || (image->page.height != 0) ||
   1094       (image->page.x != 0) || (image->page.y != 0))
   1095     (void) FormatLocaleFile(file,"  Page geometry: %.20gx%.20g%+.20g%+.20g\n",
   1096       (double) image->page.width,(double) image->page.height,(double)
   1097       image->page.x,(double) image->page.y);
   1098   if ((image->page.x != 0) || (image->page.y != 0))
   1099     (void) FormatLocaleFile(file,"  Origin geometry: %+.20g%+.20g\n",(double)
   1100       image->page.x,(double) image->page.y);
   1101   (void) FormatLocaleFile(file,"  Dispose: %s\n",CommandOptionToMnemonic(
   1102     MagickDisposeOptions,(ssize_t) image->dispose));
   1103   if (image->delay != 0)
   1104     (void) FormatLocaleFile(file,"  Delay: %.20gx%.20g\n",(double) image->delay,
   1105       (double) image->ticks_per_second);
   1106   if (image->iterations != 1)
   1107     (void) FormatLocaleFile(file,"  Iterations: %.20g\n",(double)
   1108       image->iterations);
   1109   if (image->duration != 0)
   1110     (void) FormatLocaleFile(file,"  Duration: %.20g\n",(double)
   1111       image->duration);
   1112   if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
   1113     (void) FormatLocaleFile(file,"  Scene: %.20g of %.20g\n",(double)
   1114       image->scene,(double) GetImageListLength(image));
   1115   else
   1116     if (image->scene != 0)
   1117       (void) FormatLocaleFile(file,"  Scene: %.20g\n",(double) image->scene);
   1118   (void) FormatLocaleFile(file,"  Compression: %s\n",CommandOptionToMnemonic(
   1119     MagickCompressOptions,(ssize_t) image->compression));
   1120   if (image->quality != UndefinedCompressionQuality)
   1121     (void) FormatLocaleFile(file,"  Quality: %.20g\n",(double) image->quality);
   1122   (void) FormatLocaleFile(file,"  Orientation: %s\n",CommandOptionToMnemonic(
   1123     MagickOrientationOptions,(ssize_t) image->orientation));
   1124   if (image->montage != (char *) NULL)
   1125     (void) FormatLocaleFile(file,"  Montage: %s\n",image->montage);
   1126   if (image->directory != (char *) NULL)
   1127     {
   1128       Image
   1129         *tile;
   1130 
   1131       ImageInfo
   1132         *image_info;
   1133 
   1134       register char
   1135         *p,
   1136         *q;
   1137 
   1138       WarningHandler
   1139         handler;
   1140 
   1141       /*
   1142         Display visual image directory.
   1143       */
   1144       image_info=AcquireImageInfo();
   1145       (void) CloneString(&image_info->size,"64x64");
   1146       (void) FormatLocaleFile(file,"  Directory:\n");
   1147       for (p=image->directory; *p != '\0'; p++)
   1148       {
   1149         q=p;
   1150         while ((*q != '\n') && (*q != '\0'))
   1151           q++;
   1152         (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1));
   1153         p=q;
   1154         (void) FormatLocaleFile(file,"    %s",image_info->filename);
   1155         handler=SetWarningHandler((WarningHandler) NULL);
   1156         tile=ReadImage(image_info,exception);
   1157         (void) SetWarningHandler(handler);
   1158         if (tile == (Image *) NULL)
   1159           {
   1160             (void) FormatLocaleFile(file,"\n");
   1161             continue;
   1162           }
   1163         (void) FormatLocaleFile(file," %.20gx%.20g %s\n",(double)
   1164           tile->magick_columns,(double) tile->magick_rows,tile->magick);
   1165         (void) SignatureImage(tile,exception);
   1166         ResetImagePropertyIterator(tile);
   1167         property=GetNextImageProperty(tile);
   1168         while (property != (const char *) NULL)
   1169         {
   1170           (void) FormatLocaleFile(file,"  %s:\n",property);
   1171           value=GetImageProperty(tile,property,exception);
   1172           if (value != (const char *) NULL)
   1173             (void) FormatLocaleFile(file,"%s\n",value);
   1174           property=GetNextImageProperty(tile);
   1175         }
   1176         tile=DestroyImage(tile);
   1177       }
   1178       image_info=DestroyImageInfo(image_info);
   1179     }
   1180   (void) GetImageProperty(image,"exif:*",exception);
   1181   (void) GetImageProperty(image,"icc:*",exception);
   1182   (void) GetImageProperty(image,"iptc:*",exception);
   1183   (void) GetImageProperty(image,"xmp:*",exception);
   1184   ResetImagePropertyIterator(image);
   1185   property=GetNextImageProperty(image);
   1186   if (property != (const char *) NULL)
   1187     {
   1188       /*
   1189         Display image properties.
   1190       */
   1191       (void) FormatLocaleFile(file,"  Properties:\n");
   1192       while (property != (const char *) NULL)
   1193       {
   1194         (void) FormatLocaleFile(file,"    %s: ",property);
   1195         value=GetImageProperty(image,property,exception);
   1196         if (value != (const char *) NULL)
   1197           (void) FormatLocaleFile(file,"%s\n",value);
   1198         property=GetNextImageProperty(image);
   1199       }
   1200     }
   1201   (void) FormatLocaleString(key,MagickPathExtent,"8BIM:1999,2998:#1");
   1202   value=GetImageProperty(image,key,exception);
   1203   if (value != (const char *) NULL)
   1204     {
   1205       /*
   1206         Display clipping path.
   1207       */
   1208       (void) FormatLocaleFile(file,"  Clipping path: ");
   1209       if (strlen(value) > 80)
   1210         (void) fputc('\n',file);
   1211       (void) FormatLocaleFile(file,"%s\n",value);
   1212     }
   1213   ResetImageProfileIterator(image);
   1214   name=GetNextImageProfile(image);
   1215   if (name != (char *) NULL)
   1216     {
   1217       const StringInfo
   1218         *profile;
   1219 
   1220       /*
   1221         Identify image profiles.
   1222       */
   1223       (void) FormatLocaleFile(file,"  Profiles:\n");
   1224       while (name != (char *) NULL)
   1225       {
   1226         profile=GetImageProfile(image,name);
   1227         if (profile == (StringInfo *) NULL)
   1228           continue;
   1229         (void) FormatLocaleFile(file,"    Profile-%s: %.20g bytes\n",name,
   1230           (double) GetStringInfoLength(profile));
   1231         if (LocaleCompare(name,"iptc") == 0)
   1232           {
   1233             char
   1234               *attribute,
   1235               **attribute_list;
   1236 
   1237             const char
   1238               *tag;
   1239 
   1240             long
   1241               dataset,
   1242               record,
   1243               sentinel;
   1244 
   1245             register ssize_t
   1246               j;
   1247 
   1248             size_t
   1249               length,
   1250               profile_length;
   1251 
   1252             profile_length=GetStringInfoLength(profile);
   1253             for (i=0; i < (ssize_t) profile_length; i+=(ssize_t) length)
   1254             {
   1255               length=1;
   1256               sentinel=GetStringInfoDatum(profile)[i++];
   1257               if (sentinel != 0x1c)
   1258                 continue;
   1259               dataset=GetStringInfoDatum(profile)[i++];
   1260               record=GetStringInfoDatum(profile)[i++];
   1261               switch (record)
   1262               {
   1263                 case 5: tag="Image Name"; break;
   1264                 case 7: tag="Edit Status"; break;
   1265                 case 10: tag="Priority"; break;
   1266                 case 15: tag="Category"; break;
   1267                 case 20: tag="Supplemental Category"; break;
   1268                 case 22: tag="Fixture Identifier"; break;
   1269                 case 25: tag="Keyword"; break;
   1270                 case 30: tag="Release Date"; break;
   1271                 case 35: tag="Release Time"; break;
   1272                 case 40: tag="Special Instructions"; break;
   1273                 case 45: tag="Reference Service"; break;
   1274                 case 47: tag="Reference Date"; break;
   1275                 case 50: tag="Reference Number"; break;
   1276                 case 55: tag="Created Date"; break;
   1277                 case 60: tag="Created Time"; break;
   1278                 case 65: tag="Originating Program"; break;
   1279                 case 70: tag="Program Version"; break;
   1280                 case 75: tag="Object Cycle"; break;
   1281                 case 80: tag="Byline"; break;
   1282                 case 85: tag="Byline Title"; break;
   1283                 case 90: tag="City"; break;
   1284                 case 92: tag="Sub-Location"; break;
   1285                 case 95: tag="Province State"; break;
   1286                 case 100: tag="Country Code"; break;
   1287                 case 101: tag="Country"; break;
   1288                 case 103: tag="Original Transmission Reference"; break;
   1289                 case 105: tag="Headline"; break;
   1290                 case 110: tag="Credit"; break;
   1291                 case 115: tag="Src"; break;
   1292                 case 116: tag="Copyright String"; break;
   1293                 case 120: tag="Caption"; break;
   1294                 case 121: tag="Local Caption"; break;
   1295                 case 122: tag="Caption Writer"; break;
   1296                 case 200: tag="Custom Field 1"; break;
   1297                 case 201: tag="Custom Field 2"; break;
   1298                 case 202: tag="Custom Field 3"; break;
   1299                 case 203: tag="Custom Field 4"; break;
   1300                 case 204: tag="Custom Field 5"; break;
   1301                 case 205: tag="Custom Field 6"; break;
   1302                 case 206: tag="Custom Field 7"; break;
   1303                 case 207: tag="Custom Field 8"; break;
   1304                 case 208: tag="Custom Field 9"; break;
   1305                 case 209: tag="Custom Field 10"; break;
   1306                 case 210: tag="Custom Field 11"; break;
   1307                 case 211: tag="Custom Field 12"; break;
   1308                 case 212: tag="Custom Field 13"; break;
   1309                 case 213: tag="Custom Field 14"; break;
   1310                 case 214: tag="Custom Field 15"; break;
   1311                 case 215: tag="Custom Field 16"; break;
   1312                 case 216: tag="Custom Field 17"; break;
   1313                 case 217: tag="Custom Field 18"; break;
   1314                 case 218: tag="Custom Field 19"; break;
   1315                 case 219: tag="Custom Field 20"; break;
   1316                 default: tag="unknown"; break;
   1317               }
   1318               (void) FormatLocaleFile(file,"      %s[%.20g,%.20g]: ",tag,
   1319                 (double) dataset,(double) record);
   1320               length=(size_t) (GetStringInfoDatum(profile)[i++] << 8);
   1321               length|=GetStringInfoDatum(profile)[i++];
   1322               attribute=(char *) NULL;
   1323               if (~length >= (MagickPathExtent-1))
   1324                 attribute=(char *) AcquireQuantumMemory(length+MagickPathExtent,
   1325                   sizeof(*attribute));
   1326               if (attribute != (char *) NULL)
   1327                 {
   1328                   (void) CopyMagickString(attribute,(char *)
   1329                     GetStringInfoDatum(profile)+i,length+1);
   1330                   attribute_list=StringToList(attribute);
   1331                   if (attribute_list != (char **) NULL)
   1332                     {
   1333                       for (j=0; attribute_list[j] != (char *) NULL; j++)
   1334                       {
   1335                         (void) fputs(attribute_list[j],file);
   1336                         (void) fputs("\n",file);
   1337                         attribute_list[j]=(char *) RelinquishMagickMemory(
   1338                           attribute_list[j]);
   1339                       }
   1340                       attribute_list=(char **) RelinquishMagickMemory(
   1341                         attribute_list);
   1342                     }
   1343                   attribute=DestroyString(attribute);
   1344                 }
   1345             }
   1346           }
   1347         if (image->debug != MagickFalse)
   1348           PrintStringInfo(file,name,profile);
   1349         name=GetNextImageProfile(image);
   1350       }
   1351     }
   1352   ResetImageArtifactIterator(image);
   1353   artifact=GetNextImageArtifact(image);
   1354   if (artifact != (const char *) NULL)
   1355     {
   1356       /*
   1357         Display image artifacts.
   1358       */
   1359       (void) FormatLocaleFile(file,"  Artifacts:\n");
   1360       while (artifact != (const char *) NULL)
   1361       {
   1362         (void) FormatLocaleFile(file,"    %s: ",artifact);
   1363         value=GetImageArtifact(image,artifact);
   1364         if (value != (const char *) NULL)
   1365           (void) FormatLocaleFile(file,"%s\n",value);
   1366         artifact=GetNextImageArtifact(image);
   1367       }
   1368     }
   1369   ResetImageRegistryIterator();
   1370   registry=GetNextImageRegistry();
   1371   if (registry != (const char *) NULL)
   1372     {
   1373       /*
   1374         Display image registry.
   1375       */
   1376       (void) FormatLocaleFile(file,"  Registry:\n");
   1377       while (registry != (const char *) NULL)
   1378       {
   1379         (void) FormatLocaleFile(file,"    %s: ",registry);
   1380         value=(const char *) GetImageRegistry(StringRegistryType,registry,
   1381           exception);
   1382         if (value != (const char *) NULL)
   1383           (void) FormatLocaleFile(file,"%s\n",value);
   1384         registry=GetNextImageRegistry();
   1385       }
   1386     }
   1387   (void) FormatLocaleFile(file,"  Tainted: %s\n",CommandOptionToMnemonic(
   1388     MagickBooleanOptions,(ssize_t) image->taint));
   1389   (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",MagickPathExtent,
   1390     format);
   1391   (void) FormatLocaleFile(file,"  Filesize: %s\n",format);
   1392   (void) FormatMagickSize((MagickSizeType) image->columns*image->rows,
   1393     MagickFalse,"B",MagickPathExtent,format);
   1394   if (strlen(format) > 1)
   1395     format[strlen(format)-1]='\0';
   1396   (void) FormatLocaleFile(file,"  Number pixels: %s\n",format);
   1397   (void) FormatMagickSize((MagickSizeType) ((double) image->columns*image->rows/
   1398     elapsed_time+0.5),MagickFalse,"B",MagickPathExtent,format);
   1399   (void) FormatLocaleFile(file,"  Pixels per second: %s\n",format);
   1400   (void) FormatLocaleFile(file,"  User time: %0.3fu\n",user_time);
   1401   (void) FormatLocaleFile(file,"  Elapsed time: %lu:%02lu.%03lu\n",
   1402     (unsigned long) (elapsed_time/60.0),(unsigned long) ceil(fmod(elapsed_time,
   1403     60.0)),(unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))));
   1404   (void) FormatLocaleFile(file,"  Version: %s\n",GetMagickVersion((size_t *)
   1405     NULL));
   1406   (void) fflush(file);
   1407   return(ferror(file) != 0 ? MagickFalse : MagickTrue);
   1408 }
   1409