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