root / ImageMagick / branches / ImageMagick-6.3.5 / magick / identify.c

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