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