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