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