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