root / ImageMagick / trunk / magick / identify.c

Revision 12084, 39.1 kB (checked in by cristy, 4 days ago)
Line 
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%                             John Cristy                                     %
17%                            September 1994                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 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/*
43  Include declarations.
44*/
45#include "magick/studio.h"
46#include "magick/annotate.h"
47#include "magick/artifact.h"
48#include "magick/blob.h"
49#include "magick/client.h"
50#include "magick/coder.h"
51#include "magick/color.h"
52#include "magick/configure.h"
53#include "magick/constitute.h"
54#include "magick/decorate.h"
55#include "magick/delegate.h"
56#include "magick/draw.h"
57#include "magick/effect.h"
58#include "magick/exception.h"
59#include "magick/exception-private.h"
60#include "magick/gem.h"
61#include "magick/geometry.h"
62#include "magick/identify.h"
63#include "magick/image.h"
64#include "magick/image-private.h"
65#include "magick/list.h"
66#include "magick/locale_.h"
67#include "magick/log.h"
68#include "magick/magic.h"
69#include "magick/magick.h"
70#include "magick/memory_.h"
71#include "magick/module.h"
72#include "magick/monitor.h"
73#include "magick/montage.h"
74#include "magick/option.h"
75#include "magick/pixel-private.h"
76#include "magick/prepress.h"
77#include "magick/profile.h"
78#include "magick/property.h"
79#include "magick/quantize.h"
80#include "magick/quantum.h"
81#include "magick/random_.h"
82#include "magick/registry.h"
83#include "magick/resize.h"
84#include "magick/resource_.h"
85#include "magick/signature.h"
86#include "magick/statistic.h"
87#include "magick/string_.h"
88#include "magick/timer.h"
89#include "magick/utility.h"
90#include "magick/version.h"
91#if defined(MAGICKCORE_LCMS_DELEGATE)
92#if defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
93#include <lcms/lcms.h>
94#else
95#include "lcms.h"
96#endif
97#endif
98
99/*
100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101%                                                                             %
102%                                                                             %
103%                                                                             %
104%   I d e n t i f y I m a g e                                                 %
105%                                                                             %
106%                                                                             %
107%                                                                             %
108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109%
110%  IdentifyImage() identifies an image by printing its attributes to the file.
111%  Attributes include the image width, height, size, and others.
112%
113%  The format of the IdentifyImage method is:
114%
115%      MagickBooleanType IdentifyImage(Image *image,FILE *file,
116%        const MagickBooleanType verbose)
117%
118%  A description of each parameter follows:
119%
120%    o image: the image.
121%
122%    o file: the file, typically stdout.
123%
124%    o verbose: A value other than zero prints more detailed information
125%      about the image.
126%
127*/
128MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
129  const MagickBooleanType verbose)
130{
131#define IdentifyFormat "    %s:\n      min: " QuantumFormat  \
132  " (%g)\n      max: " QuantumFormat " (%g)\n"  \
133  "      mean: %g (%g)\n      standard deviation: %g (%g)\n"
134
135  char
136    color[MaxTextExtent],
137    format[MaxTextExtent],
138    key[MaxTextExtent];
139
140  ColorspaceType
141    colorspace;
142
143  const char
144    *artifact,
145    *name,
146    *property,
147    *registry,
148    *value;
149
150  const MagickInfo
151    *magick_info;
152
153  const PixelPacket
154    *pixels;
155
156  double
157    elapsed_time,
158    user_time;
159
160  ExceptionInfo
161    *exception;
162
163  ImageType
164    type;
165
166  long
167    y;
168
169  MagickBooleanType
170    ping;
171
172  register long
173    i,
174    x;
175
176  unsigned long
177    scale;
178
179  assert(image != (Image *) NULL);
180  assert(image->signature == MagickSignature);
181  if (image->debug != MagickFalse)
182    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
183  if (file == (FILE *) NULL)
184    file=stdout;
185  *format='\0';
186  elapsed_time=GetElapsedTime(&image->timer);
187  user_time=GetUserTime(&image->timer);
188  GetTimerInfo(&image->timer);
189  if (verbose == MagickFalse)
190    {
191      /*
192        Display summary info about the image.
193      */
194      if (*image->magick_filename != '\0')
195        if (LocaleCompare(image->magick_filename,image->filename) != 0)
196          (void) fprintf(file,"%s=>",image->magick_filename);
197       if ((GetPreviousImageInList(image) == (Image *) NULL) &&
198           (GetNextImageInList(image) == (Image *) NULL) && (image->scene == 0))
199        (void) fprintf(file,"%s ",image->filename);
200      else
201        (void) fprintf(file,"%s[%lu] ",image->filename,image->scene);
202      (void) fprintf(file,"%s ",image->magick);
203      if ((image->magick_columns != 0) || (image->magick_rows != 0))
204        if ((image->magick_columns != image->columns) ||
205            (image->magick_rows != image->rows))
206          (void) fprintf(file,"%lux%lu=>",image->magick_columns,
207            image->magick_rows);
208      (void) fprintf(file,"%lux%lu ",image->columns,image->rows);
209      if ((image->page.width != 0) || (image->page.height != 0) ||
210          (image->page.x != 0) || (image->page.y != 0))
211        (void) fprintf(file,"%lux%lu%+ld%+ld ",image->page.width,
212          image->page.height,image->page.x,image->page.y);
213      (void) fprintf(file,"%lu-bit ",image->depth);
214      if (image->type != UndefinedType)
215        (void) fprintf(file,"%s ",MagickOptionToMnemonic(MagickTypeOptions,
216          (long) image->type));
217      if (image->storage_class == DirectClass)
218        {
219          (void) fprintf(file,"DirectClass ");
220          if (image->total_colors != 0)
221            {
222              (void) FormatMagickSize(image->total_colors,format);
223              (void) fprintf(file,"%s ",format);
224            }
225        }
226      else
227        if (image->total_colors <= image->colors)
228          (void) fprintf(file,"PseudoClass %luc ",image->colors);
229        else
230          (void) fprintf(file,"PseudoClass %lu=>%luc ",image->total_colors,
231            image->colors);
232      if (image->error.mean_error_per_pixel != 0.0)
233        (void) fprintf(file,"%ld/%f/%fdb ",(long)
234          (image->error.mean_error_per_pixel+0.5),
235          image->error.normalized_mean_error,
236          image->error.normalized_maximum_error);
237      if (GetBlobSize(image) != 0)
238        {
239          (void) FormatMagickSize(GetBlobSize(image),format);
240          (void) fprintf(file,"%s ",format);
241        }
242      if (elapsed_time > 0.06)
243        (void) fprintf(file,"%0.3fu %ld:%02ld",user_time,(long)
244          (elapsed_time/60.0+0.5),(long) ceil(fmod(elapsed_time,60.0)));
245      (void) fprintf(file,"\n");
246      (void) fflush(file);
247      return(ferror(file) != 0 ? MagickFalse : MagickTrue);
248    }
249  /*
250    Display verbose info about the image.
251  */
252  exception=AcquireExceptionInfo();
253  pixels=AcquireImagePixels(image,0,0,1,1,exception);
254  exception=DestroyExceptionInfo(exception);
255  ping=pixels == (const PixelPacket *) NULL ? MagickTrue : MagickFalse;
256  type=GetImageType(image,&image->exception);
257  (void) SignatureImage(image);
258  (void) fprintf(file,"Image: %s\n",image->filename);
259  if (*image->magick_filename != '\0')
260    if (LocaleCompare(image->magick_filename,image->filename) != 0)
261      {
262        char
263          filename[MaxTextExtent];
264
265        GetPathComponent(image->magick_filename,TailPath,filename);
266        (void) fprintf(file,"  Base filename: %s\n",filename);
267      }
268  magick_info=GetMagickInfo(image->magick,&image->exception);
269  if ((magick_info == (const MagickInfo *) NULL) ||
270      (*GetMagickDescription(magick_info) == '\0'))
271    (void) fprintf(file,"  Format: %s\n",image->magick);
272  else
273    (void) fprintf(file,"  Format: %s (%s)\n",image->magick,
274      GetMagickDescription(magick_info));
275  (void) fprintf(file,"  Class: %s\n",MagickOptionToMnemonic(MagickClassOptions,
276    (long) image->storage_class));
277  (void) fprintf(file,"  Geometry: %lux%lu%+ld%+ld\n",image->columns,
278    image->rows,image->tile_offset.x,image->tile_offset.y);
279  if ((image->magick_columns != 0) || (image->magick_rows != 0))
280    if ((image->magick_columns != image->columns) ||
281        (image->magick_rows != image->rows))
282      (void) fprintf(file,"  Base geometry: %lux%lu\n",image->magick_columns,
283        image->magick_rows);
284  if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
285    {
286      (void) fprintf(file,"  Resolution: %gx%g\n",image->x_resolution,
287        image->y_resolution);
288      (void) fprintf(file,"  Print size: %gx%g\n",(double) image->columns/
289        image->x_resolution,(double) image->rows/image->y_resolution);
290    }
291  (void) fprintf(file,"  Units: %s\n",MagickOptionToMnemonic(
292    MagickResolutionOptions,(long) image->units));
293  (void) fprintf(file,"  Type: %s\n",MagickOptionToMnemonic(MagickTypeOptions,
294    (long) type));
295  if (image->type != UndefinedType)
296    (void) fprintf(file,"  Base type: %s\n",MagickOptionToMnemonic(
297      MagickTypeOptions,(long) image->type));
298  (void) fprintf(file,"  Endianess: %s\n",MagickOptionToMnemonic(
299    MagickEndianOptions,(long) image->endian));
300  /*
301    Detail channel depth and extrema.
302  */
303  colorspace=image->colorspace;
304  if (IsGrayImage(image,&image->exception) != MagickFalse)
305    colorspace=GRAYColorspace;
306  (void) fprintf(file,"  Colorspace: %s\n",MagickOptionToMnemonic(
307    MagickColorspaceOptions,(long) colorspace));
308  if (ping == MagickFalse)
309    {
310      ChannelStatistics
311        *channel_statistics;
312
313      unsigned long
314        depth;
315
316      depth=GetImageDepth(image,&image->exception);
317      if (image->depth == depth)
318        (void) fprintf(file,"  Depth: %lu-bit\n",image->depth);
319      else
320        (void) fprintf(file,"  Depth: %lu/%lu-bit\n",image->depth,depth);
321      channel_statistics=GetImageChannelStatistics(image,&image->exception);
322      (void) fprintf(file,"  Channel depth:\n");
323      switch (colorspace)
324      {
325        case RGBColorspace:
326        default:
327        {
328          (void) fprintf(file,"    red: %lu-bit\n",
329            channel_statistics[RedChannel].depth);
330          (void) fprintf(file,"    green: %lu-bit\n",
331            channel_statistics[GreenChannel].depth);
332          (void) fprintf(file,"    blue: %lu-bit\n",
333            channel_statistics[BlueChannel].depth);
334          if (image->matte != MagickFalse)
335            (void) fprintf(file,"    alpha: %lu-bit\n",
336              channel_statistics[OpacityChannel].depth);
337          break;
338        }
339        case CMYKColorspace:
340        {
341          (void) fprintf(file,"    cyan: %lu-bit\n",
342            channel_statistics[CyanChannel].depth);
343          (void) fprintf(file,"    magenta: %lu-bit\n",
344            channel_statistics[MagentaChannel].depth);
345          (void) fprintf(file,"    yellow: %lu-bit\n",
346            channel_statistics[YellowChannel].depth);
347          (void) fprintf(file,"    black: %lu-bit\n",
348            channel_statistics[BlackChannel].depth);
349          if (image->matte != MagickFalse)
350            (void) fprintf(file,"    alpha: %lu-bit\n",
351              channel_statistics[OpacityChannel].depth);
352          break;
353        }
354        case GRAYColorspace:
355        {
356          (void) fprintf(file,"    gray: %lu-bit\n",
357            channel_statistics[GrayChannel].depth);
358          if (image->matte != MagickFalse)
359            (void) fprintf(file,"    alpha: %lu-bit\n",
360              channel_statistics[OpacityChannel].depth);
361          break;
362        }
363      }
364      scale=QuantumRange/((unsigned long) QuantumRange >> ((unsigned long)
365        MAGICKCORE_QUANTUM_DEPTH-channel_statistics[AllChannels].depth));
366      (void) fprintf(file,"  Channel statistics:\n");
367      switch (colorspace)
368      {
369        case RGBColorspace:
370        default:
371        {
372          (void) fprintf(file,IdentifyFormat,"red",(Quantum)
373            (channel_statistics[RedChannel].minima/scale),(double)
374            channel_statistics[RedChannel].minima/(double) QuantumRange,
375            (Quantum) (channel_statistics[RedChannel].maxima/scale),(double)
376            channel_statistics[RedChannel].maxima/(double) QuantumRange,
377            channel_statistics[RedChannel].mean/(double) scale,
378            channel_statistics[RedChannel].mean/(double) QuantumRange,
379            channel_statistics[RedChannel].standard_deviation/(double) scale,
380            channel_statistics[RedChannel].standard_deviation/(double)
381            QuantumRange);
382          (void) fprintf(file,IdentifyFormat,"green",(Quantum)
383            (channel_statistics[GreenChannel].minima/scale),(double)
384            channel_statistics[GreenChannel].minima/(double) QuantumRange,
385            (Quantum) (channel_statistics[GreenChannel].maxima/scale),(double)
386            channel_statistics[GreenChannel].maxima/(double) QuantumRange,
387            channel_statistics[GreenChannel].mean/(double) scale,
388            channel_statistics[GreenChannel].mean/(double) QuantumRange,
389            channel_statistics[GreenChannel].standard_deviation/(double) scale,
390            channel_statistics[GreenChannel].standard_deviation/(double)
391            QuantumRange);
392          (void) fprintf(file,IdentifyFormat,"blue",(Quantum)
393            (channel_statistics[BlueChannel].minima/scale),(double)
394            channel_statistics[BlueChannel].minima/(double) QuantumRange,
395            (Quantum) (channel_statistics[BlueChannel].maxima/scale),(double)
396            channel_statistics[BlueChannel].maxima/(double) QuantumRange,
397            channel_statistics[BlueChannel].mean/(double) scale,
398            channel_statistics[BlueChannel].mean/(double) QuantumRange,
399            channel_statistics[BlueChannel].standard_deviation/(double) scale,
400            channel_statistics[BlueChannel].standard_deviation/(double)
401            QuantumRange);
402          break;
403        }
404        case CMYKColorspace:
405        {
406          (void) fprintf(file,IdentifyFormat,"cyan",(Quantum)
407            (channel_statistics[CyanChannel].minima/scale),(double)
408            channel_statistics[CyanChannel].minima/(double) QuantumRange,
409            (Quantum) (channel_statistics[CyanChannel].maxima/scale),(double)
410            channel_statistics[CyanChannel].maxima/(double) QuantumRange,
411            channel_statistics[CyanChannel].mean/(double) scale,
412            channel_statistics[CyanChannel].mean/(double) QuantumRange,
413            channel_statistics[CyanChannel].standard_deviation/(double) scale,
414            channel_statistics[CyanChannel].standard_deviation/(double)
415            QuantumRange);
416          (void) fprintf(file,IdentifyFormat,"magenta",(Quantum)
417            (channel_statistics[MagentaChannel].minima/scale),(double)
418            channel_statistics[MagentaChannel].minima/(double) QuantumRange,
419            (Quantum) (channel_statistics[MagentaChannel].maxima/scale),(double)
420            channel_statistics[MagentaChannel].maxima/(double) QuantumRange,
421            channel_statistics[MagentaChannel].mean/(double) scale,
422            channel_statistics[MagentaChannel].mean/(double) QuantumRange,
423            channel_statistics[MagentaChannel].standard_deviation/(double)
424            scale,channel_statistics[MagentaChannel].standard_deviation/(double)
425            QuantumRange);
426          (void) fprintf(file,IdentifyFormat,"yellow",(Quantum)
427            (channel_statistics[YellowChannel].minima/scale),(double)
428            channel_statistics[YellowChannel].minima/(double) QuantumRange,
429            (Quantum) (channel_statistics[YellowChannel].maxima/scale),(double)
430            channel_statistics[YellowChannel].maxima/(double) QuantumRange,
431            channel_statistics[YellowChannel].mean/(double) scale,
432            channel_statistics[YellowChannel].mean/(double) QuantumRange,
433            channel_statistics[YellowChannel].standard_deviation/(double) scale,
434            channel_statistics[YellowChannel].standard_deviation/(double)
435            QuantumRange);
436          (void) fprintf(file,IdentifyFormat,"black",(Quantum)
437            (channel_statistics[BlackChannel].minima/scale),(double)
438            channel_statistics[BlackChannel].minima/(double) QuantumRange,
439            (Quantum) (channel_statistics[BlackChannel].maxima/scale),(double)
440            channel_statistics[BlackChannel].maxima/(double) QuantumRange,
441            channel_statistics[BlackChannel].mean/(double) scale,
442            channel_statistics[BlackChannel].mean/(double) QuantumRange,
443            channel_statistics[BlackChannel].standard_deviation/(double) scale,
444            channel_statistics[BlackChannel].standard_deviation/(double)
445            QuantumRange);
446          break;
447        }
448        case GRAYColorspace:
449        {
450          (void) fprintf(file,IdentifyFormat,"gray",(Quantum)
451            (channel_statistics[GrayChannel].minima/scale),(double)
452            channel_statistics[GrayChannel].minima/(double) QuantumRange,
453            (Quantum) (channel_statistics[GrayChannel].maxima/scale),(double)
454            channel_statistics[GrayChannel].maxima/(double) QuantumRange,
455            channel_statistics[GrayChannel].mean/(double) scale,
456            channel_statistics[GrayChannel].mean/(double) QuantumRange,
457            channel_statistics[GrayChannel].standard_deviation/(double) scale,
458            channel_statistics[GrayChannel].standard_deviation/(double)
459            QuantumRange);
460          break;
461        }
462      }
463      if (image->matte != MagickFalse)
464        (void) fprintf(file,IdentifyFormat,"alpha",(Quantum) ((QuantumRange-
465          channel_statistics[AlphaChannel].minima)/scale),(double)
466          (QuantumRange-channel_statistics[AlphaChannel].minima)/(double)
467          QuantumRange,(Quantum) ((QuantumRange-
468          channel_statistics[AlphaChannel].maxima)/scale),(double)
469          (QuantumRange-channel_statistics[AlphaChannel].maxima)/(double)
470          QuantumRange,(QuantumRange-channel_statistics[AlphaChannel].mean)/
471          (double) scale,(QuantumRange-channel_statistics[AlphaChannel].mean)/
472          (double) QuantumRange,
473          channel_statistics[AlphaChannel].standard_deviation/(double) scale,
474          channel_statistics[AlphaChannel].standard_deviation/(double)
475          QuantumRange);
476      channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
477        channel_statistics);
478      if (colorspace == CMYKColorspace)
479        (void) fprintf(file,"  Total ink density: %.0f%%\n",100.0*
480          GetImageTotalInkDensity(image)/(double) QuantumRange);
481      x=0;
482      if (image->matte != MagickFalse)
483        {
484          register const IndexPacket
485            *indexes;
486
487          register const PixelPacket
488            *p;
489
490          p=(PixelPacket *) NULL;
491          indexes=(IndexPacket *) NULL;
492          for (y=0; y < (long) image->rows; y++)
493          {
494            p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
495            if (p == (const PixelPacket *) NULL)
496              break;
497            indexes=AcquireIndexes(image);
498            for (x=0; x < (long) image->columns; x++)
499            {
500              if (p->opacity == (Quantum) TransparentOpacity)
501                break;
502              p++;
503            }
504            if (x < (long) image->columns)
505              break;
506          }
507          if ((x < (long) image->columns) || (y < (long) image->rows))
508            {
509              char
510                tuple[MaxTextExtent];
511
512              MagickPixelPacket
513                pixel;
514
515              GetMagickPixelPacket(image,&pixel);
516              SetMagickPixelPacket(image,p,indexes+x,&pixel);
517              (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
518                &image->exception);
519              (void) fprintf(file,"  Alpha: %s ",tuple);
520              GetColorTuple(&pixel,MagickTrue,tuple);
521              (void) fprintf(file,"  %s\n",tuple);
522            }
523        }
524      if (ping == MagickFalse)
525        {
526          artifact=GetImageArtifact(image,"identify:unique");
527          if ((artifact != (const char *) NULL) &&
528              (IsMagickTrue(artifact) != MagickFalse))
529            (void) fprintf(file,"  Colors: %lu\n",GetNumberColors(image,
530              (FILE *) NULL,&image->exception));
531          if (IsHistogramImage(image,&image->exception) != MagickFalse)
532            {
533              (void) fprintf(file,"  Histogram:\n");
534              (void) GetNumberColors(image,file,&image->exception);
535            }
536        }
537    }
538  if (image->storage_class == PseudoClass)
539    {
540      (void) fprintf(file,"  Colormap: %lu\n",image->colors);
541      if (image->colors <= 1024)
542        {
543          char
544            color[MaxTextExtent],
545            hex[MaxTextExtent],
546            tuple[MaxTextExtent];
547
548          MagickPixelPacket
549            pixel;
550
551          register PixelPacket
552            *p;
553
554          GetMagickPixelPacket(image,&pixel);
555          p=image->colormap;
556          for (i=0; i < (long) image->colors; i++)
557          {
558            SetMagickPixelPacket(image,p,(IndexPacket *) NULL,&pixel);
559            (void) CopyMagickString(tuple,"(",MaxTextExtent);
560            ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
561            (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
562            ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
563            (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
564            ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
565            if (pixel.colorspace == CMYKColorspace)
566              {
567                (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
568                ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,
569                  tuple);
570              }
571            if (pixel.matte != MagickFalse)
572              {
573                (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
574                ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,
575                  tuple);
576              }
577            (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
578            (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,
579              &image->exception);
580            GetColorTuple(&pixel,MagickTrue,hex);
581            (void) fprintf(file,"  %8ld: %s %s %s\n",i,tuple,hex,color);
582            p++;
583          }
584        }
585    }
586  if (image->error.mean_error_per_pixel != 0.0)
587    (void) fprintf(file,"  Mean error per pixel: %g\n",
588      image->error.mean_error_per_pixel);
589  if (image->error.normalized_mean_error != 0.0)
590    (void) fprintf(file,"  Normalized mean error: %g\n",
591      image->error.normalized_mean_error);
592  if (image->error.normalized_maximum_error != 0.0)
593    (void) fprintf(file,"  Normalized maximum error: %g\n",
594      image->error.normalized_maximum_error);
595  (void) fprintf(file,"  Rendering intent: %s\n",MagickOptionToMnemonic(
596    MagickIntentOptions,(long) image->rendering_intent));
597  if (image->gamma != 0.0)
598    (void) fprintf(file,"  Gamma: %g\n",image->gamma);
599  if ((image->chromaticity.red_primary.x != 0.0) ||
600      (image->chromaticity.green_primary.x != 0.0) ||
601      (image->chromaticity.blue_primary.x != 0.0) ||
602      (image->chromaticity.white_point.x != 0.0))
603    {
604      /*
605        Display image chromaticity.
606      */
607      (void) fprintf(file,"  Chromaticity:\n");
608      (void) fprintf(file,"    red primary: (%g,%g)\n",
609        image->chromaticity.red_primary.x,image->chromaticity.red_primary.y);
610      (void) fprintf(file,"    green primary: (%g,%g)\n",
611        image->chromaticity.green_primary.x,
612        image->chromaticity.green_primary.y);
613      (void) fprintf(file,"    blue primary: (%g,%g)\n",
614        image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y);
615      (void) fprintf(file,"    white point: (%g,%g)\n",
616        image->chromaticity.white_point.x,image->chromaticity.white_point.y);
617    }
618  if ((image->extract_info.width*image->extract_info.height) != 0)
619    (void) fprintf(file,"  Tile geometry: %lux%lu%+ld%+ld\n",
620      image->extract_info.width,image->extract_info.height,
621      image->extract_info.x,image->extract_info.y);
622  (void) fprintf(file,"  Interlace: %s\n",MagickOptionToMnemonic(
623    MagickInterlaceOptions,(long) image->interlace));
624  (void) QueryColorname(image,&image->background_color,SVGCompliance,color,
625    &image->exception);
626  (void) fprintf(file,"  Background color: %s\n",color);
627  (void) QueryColorname(image,&image->border_color,SVGCompliance,color,
628    &image->exception);
629  (void) fprintf(file,"  Border color: %s\n",color);
630  (void) QueryColorname(image,&image->matte_color,SVGCompliance,color,
631    &image->exception);
632  (void) fprintf(file,"  Matte color: %s\n",color);
633  (void) QueryColorname(image,&image->transparent_color,SVGCompliance,color,
634    &image->exception);
635  (void) fprintf(file,"  Transparent color: %s\n",color);
636  if ((image->page.width != 0) || (image->page.height != 0) ||
637      (image->page.x != 0) || (image->page.y != 0))
638    (void) fprintf(file,"  Page geometry: %lux%lu%+ld%+ld\n",image->page.width,
639      image->page.height,image->page.x,image->page.y);
640  if ((image->page.x != 0) || (image->page.y != 0))
641    (void) fprintf(file,"  Origin geometry: %+ld%+ld\n",image->page.x,
642      image->page.y);
643  (void) fprintf(file,"  Dispose: %s\n",MagickOptionToMnemonic(
644    MagickDisposeOptions,(long) image->dispose));
645  if (image->delay != 0)
646    (void) fprintf(file,"  Delay: %lux%ld\n",image->delay,
647      image->ticks_per_second);
648  if (image->iterations != 1)
649    (void) fprintf(file,"  Iterations: %lu\n",image->iterations);
650  if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
651    (void) fprintf(file,"  Scene: %lu of %lu\n",image->scene,
652      GetImageListLength(image));
653  else
654    if (image->scene != 0)
655      (void) fprintf(file,"  Scene: %lu\n",image->scene);
656  (void) fprintf(file,"  Compression: %s\n",MagickOptionToMnemonic(
657    MagickCompressOptions,(long) image->compression));
658  if (image->quality != UndefinedCompressionQuality)
659    (void) fprintf(file,"  Quality: %lu\n",image->quality);
660  (void) fprintf(file,"  Orientation: %s\n",MagickOptionToMnemonic(
661    MagickOrientationOptions,(long) image->orientation));
662  if (image->montage != (char *) NULL)
663    (void) fprintf(file,"  Montage: %s\n",image->montage);
664  if (image->directory != (char *) NULL)
665    {
666      Image
667        *tile;
668
669      ImageInfo
670        *image_info;
671
672      register char
673        *p,
674        *q;
675
676      WarningHandler
677        handler;
678
679      /*
680        Display visual image directory.
681      */
682      image_info=AcquireImageInfo();
683      (void) CloneString(&image_info->size,"64x64");
684      (void) fprintf(file,"  Directory:\n");
685      for (p=image->directory; *p != '\0'; p++)
686      {
687        q=p;
688        while ((*q != '\n') && (*q != '\0'))
689          q++;
690        (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1));
691        p=q;
692        (void) fprintf(file,"    %s",image_info->filename);
693        handler=SetWarningHandler((WarningHandler) NULL);
694        tile=ReadImage(image_info,&image->exception);
695        (void) SetWarningHandler(handler);
696        if (tile == (Image *) NULL)
697          {
698            (void) fprintf(file,"\n");
699            continue;
700          }
701        (void) fprintf(file," %lux%lu %s\n",tile->magick_columns,
702          tile->magick_rows,tile->magick);
703        (void) SignatureImage(tile);
704        ResetImagePropertyIterator(tile);
705        property=GetNextImageProperty(tile);
706        while (property != (const char *) NULL)
707        {
708          (void) fprintf(file,"  %s:\n",property);
709          value=GetImageProperty(tile,property);
710          if (value != (const char *) NULL)
711            (void) fprintf(file,"%s\n",value);
712          property=GetNextImageProperty(tile);
713        }
714        tile=DestroyImage(tile);
715      }
716      image_info=DestroyImageInfo(image_info);
717    }
718  (void) GetImageProperty(image,"exif:*");
719  ResetImagePropertyIterator(image);
720  property=GetNextImageProperty(image);
721  if (property != (const char *) NULL)
722    {
723      /*
724        Display image properties.
725      */
726      (void) fprintf(file,"  Properties:\n");
727      while (property != (const char *) NULL)
728      {
729        (void) fprintf(file,"    %c",*property);
730        if (strlen(property) > 1)
731          (void) fprintf(file,"%s: ",property+1);
732        if (strlen(property) > 80)
733          (void) fputc('\n',file);
734        value=GetImageProperty(image,property);
735        if (value != (const char *) NULL)
736          (void) fprintf(file,"%s\n",value);
737        property=GetNextImageProperty(image);
738      }
739    }
740  (void) FormatMagickString(key,MaxTextExtent,"8BIM:1999,2998:#1");
741  value=GetImageProperty(image,key);
742  if (value != (const char *) NULL)
743    {
744      /*
745        Display clipping path.
746      */
747      (void) fprintf(file,"  Clipping path: ");
748      if (strlen(value) > 80)
749        (void) fputc('\n',file);
750      (void) fprintf(file,"%s\n",value);
751    }
752  ResetImageProfileIterator(image);
753  name=GetNextImageProfile(image);
754  if (name != (char *) NULL)
755    {
756      const StringInfo
757        *profile;
758
759      /*
760        Identify image profiles.
761      */
762      (void) fprintf(file,"  Profiles:\n");
763      while (name != (char *) NULL)
764      {
765        profile=GetImageProfile(image,name);
766        if (profile == (StringInfo *) NULL)
767          continue;
768        (void) fprintf(file,"    Profile-%s: %lu bytes\n",name,(unsigned long)
769          GetStringInfoLength(profile));
770#if defined(MAGICKCORE_LCMS_DELEGATE)
771        if ((LocaleCompare(name,"icc") == 0) ||
772            (LocaleCompare(name,"icm") == 0))
773          {
774            cmsHPROFILE
775              icc_profile;
776
777            icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
778              (DWORD) GetStringInfoLength(profile));
779            if (icc_profile != (cmsHPROFILE *) NULL)
780              {
781                const char
782                  *name;
783
784                name=cmsTakeProductName(icc_profile);
785                if (name != (const char *) NULL)
786                  (void) fprintf(file,"      %s\n",name);
787                (void) cmsCloseProfile(icc_profile);
788              }
789          }
790#endif
791        if (LocaleCompare(name,"8bim") == 0)
792          {
793            char
794              *attribute,
795              **attribute_list;
796
797            const char
798              *tag;
799
800            long
801              dataset,
802              record,
803              sentinel;
804
805            register long
806              j;
807
808            size_t
809              length,
810              profile_length;
811
812            /*
813              Identify IPTC data.
814            */
815            profile_length=GetStringInfoLength(profile);
816            for (i=0; i < (long) profile_length; i+=(long) length)
817            {
818              length=1;
819              sentinel=GetStringInfoDatum(profile)[i++];
820              if (sentinel != 0x1c)
821                continue;
822              dataset=GetStringInfoDatum(profile)[i++];
823              record=GetStringInfoDatum(profile)[i++];
824              switch (record)
825              {
826                case 5: tag="Image Name"; break;
827                case 7: tag="Edit Status"; break;
828                case 10: tag="Priority"; break;
829                case 15: tag="Category"; break;
830                case 20: tag="Supplemental Category"; break;
831                case 22: tag="Fixture Identifier"; break;
832                case 25: tag="Keyword"; break;
833                case 30: tag="Release Date"; break;
834                case 35: tag="Release Time"; break;
835                case 40: tag="Special Instructions"; break;
836                case 45: tag="Reference Service"; break;
837                case 47: tag="Reference Date"; break;
838                case 50: tag="Reference Number"; break;
839                case 55: tag="Created Date"; break;
840                case 60: tag="Created Time"; break;
841                case 65: tag="Originating Program"; break;
842                case 70: tag="Program Version"; break;
843                case 75: tag="Object Cycle"; break;
844                case 80: tag="Byline"; break;
845                case 85: tag="Byline Title"; break;
846                case 90: tag="City"; break;
847                case 95: tag="Province State"; break;
848                case 100: tag="Country Code"; break;
849                case 101: tag="Country"; break;
850                case 103: tag="Original Transmission Reference"; break;
851                case 105: tag="Headline"; break;
852                case 110: tag="Credit"; break;
853                case 115: tag="Src"; break;
854                case 116: tag="Copyright String"; break;
855                case 120: tag="Caption"; break;
856                case 121: tag="Local Caption"; break;
857                case 122: tag="Caption Writer"; break;
858                case 200: tag="Custom Field 1"; break;
859                case 201: tag="Custom Field 2"; break;