MagickCore  6.9.13-19
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) < 0.5 ? MagickTrue : MagickFalse;
357  break;
358  }
359  case GreenChannel:
360  {
361  match=fabs((double) p->green-target) < 0.5 ? MagickTrue :
362  MagickFalse;
363  break;
364  }
365  case BlueChannel:
366  {
367  match=fabs((double) p->blue-target) < 0.5 ? MagickTrue :
368  MagickFalse;
369  break;
370  }
371  case AlphaChannel:
372  {
373  match=fabs((double) p->opacity-target) < 0.5 ? MagickTrue :
374  MagickFalse;
375  break;
376  }
377  default:
378  break;
379  }
380  if (match != MagickFalse)
381  {
382  if ((max_locations != 0) && (n >= (ssize_t) max_locations))
383  break;
384  (void) FormatLocaleFile(file," %.20g,%.20g",(double) x,(double) y);
385  n++;
386  }
387  p++;
388  }
389  if (x < (ssize_t) image->columns)
390  break;
391  }
392  (void) FormatLocaleFile(file,"\n");
393  return(n);
394 }
395 
396 static ssize_t PrintChannelMoments(FILE *file,const ChannelType channel,
397  const char *name,const double scale,const ChannelMoments *channel_moments)
398 {
399  double
400  powers[MaximumNumberOfImageMoments] =
401  { 1.0, 2.0, 3.0, 3.0, 6.0, 4.0, 6.0, 4.0 };
402 
403  ssize_t
404  i;
405 
406  ssize_t
407  n;
408 
409  n=FormatLocaleFile(file," %s:\n",name);
410  n+=FormatLocaleFile(file," Centroid: %.*g,%.*g\n",
411  GetMagickPrecision(),channel_moments[channel].centroid.x,
412  GetMagickPrecision(),channel_moments[channel].centroid.y);
413  n+=FormatLocaleFile(file," Ellipse Semi-Major/Minor axis: %.*g,%.*g\n",
414  GetMagickPrecision(),channel_moments[channel].ellipse_axis.x,
415  GetMagickPrecision(),channel_moments[channel].ellipse_axis.y);
416  n+=FormatLocaleFile(file," Ellipse angle: %.*g\n",
417  GetMagickPrecision(),channel_moments[channel].ellipse_angle);
418  n+=FormatLocaleFile(file," Ellipse eccentricity: %.*g\n",
419  GetMagickPrecision(),channel_moments[channel].ellipse_eccentricity);
420  n+=FormatLocaleFile(file," Ellipse intensity: %.*g (%.*g)\n",
421  GetMagickPrecision(),pow(scale,powers[0])*
422  channel_moments[channel].ellipse_intensity,GetMagickPrecision(),
423  channel_moments[channel].ellipse_intensity);
424  for (i=0; i < MaximumNumberOfImageMoments; i++)
425  n+=FormatLocaleFile(file," I%.20g: %.*g (%.*g)\n",i+1.0,
426  GetMagickPrecision(),channel_moments[channel].I[i]/pow(scale,powers[i]),
427  GetMagickPrecision(),channel_moments[channel].I[i]);
428  return(n);
429 }
430 
431 static ssize_t PrintChannelPerceptualHash(FILE *file,const ChannelType channel,
432  const char *name,const ChannelPerceptualHash *channel_phash)
433 {
434  ssize_t
435  i;
436 
437  ssize_t
438  n;
439 
440  n=FormatLocaleFile(file," %s:\n",name);
441  for (i=0; i < MaximumNumberOfPerceptualHashes; i++)
442  n+=FormatLocaleFile(file," PH%.20g: %.*g, %.*g\n",i+1.0,
443  GetMagickPrecision(),channel_phash[channel].P[i],
444  GetMagickPrecision(),channel_phash[channel].Q[i]);
445  return(n);
446 }
447 
448 static ssize_t PrintChannelStatistics(FILE *file,const ChannelType channel,
449  const char *name,const double scale,
450  const ChannelStatistics *channel_statistics)
451 {
452 #define StatisticsFormat " %s:\n min: %.*g (%.*g)\n " \
453  "max: %.*g (%.*g)\n mean: %.*g (%.*g)\n " \
454  "standard deviation: %.*g (%.*g)\n kurtosis: %.*g\n " \
455  "skewness: %.*g\n entropy: %.*g\n"
456 
457  ssize_t
458  n;
459 
460  n=FormatLocaleFile(file,StatisticsFormat,name,GetMagickPrecision(),
461  (double) ClampToQuantum((MagickRealType) (scale*
462  channel_statistics[channel].minima)),GetMagickPrecision(),
463  channel_statistics[channel].minima/(double) QuantumRange,
464  GetMagickPrecision(),(double) ClampToQuantum((MagickRealType) (scale*
465  channel_statistics[channel].maxima)),GetMagickPrecision(),
466  channel_statistics[channel].maxima/(double) QuantumRange,
467  GetMagickPrecision(),scale*channel_statistics[channel].mean,
468  GetMagickPrecision(),channel_statistics[channel].mean/(double) QuantumRange,
469  GetMagickPrecision(),scale*channel_statistics[channel].standard_deviation,
470  GetMagickPrecision(),channel_statistics[channel].standard_deviation/
471  (double) QuantumRange,GetMagickPrecision(),
472  channel_statistics[channel].kurtosis,GetMagickPrecision(),
473  channel_statistics[channel].skewness,GetMagickPrecision(),
474  channel_statistics[channel].entropy);
475  return(n);
476 }
477 
478 MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
479  const MagickBooleanType verbose)
480 {
481  char
482  color[MaxTextExtent],
483  format[MaxTextExtent],
484  key[MaxTextExtent];
485 
487  *channel_features;
488 
490  *channel_moments;
491 
493  *channel_phash;
494 
496  *channel_statistics;
497 
498  ColorspaceType
499  colorspace;
500 
501  const char
502  *artifact,
503  *locate,
504  *name,
505  *property,
506  *registry,
507  *value;
508 
509  const MagickInfo
510  *magick_info;
511 
512  const PixelPacket
513  *pixels;
514 
515  double
516  elapsed_time,
517  scale,
518  user_time;
519 
521  *exception;
522 
523  ImageType
524  type;
525 
526  int
527  expired;
528 
529  MagickBooleanType
530  ping;
531 
532  size_t
533  depth,
534  distance;
535 
536  ssize_t
537  i,
538  x,
539  y;
540 
541  struct stat
542  properties;
543 
544  assert(image != (Image *) NULL);
545  assert(image->signature == MagickCoreSignature);
546  if (IsEventLogging() != MagickFalse)
547  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
548  if (file == (FILE *) NULL)
549  file=stdout;
550  exception=AcquireExceptionInfo();
551  colorspace=image->colorspace;
552  locate=GetImageArtifact(image,"identify:locate");
553  if (locate != (const char *) NULL)
554  {
555  const char
556  *limit;
557 
558  size_t
559  max_locations;
560 
561  StatisticType
562  statistic_type;
563 
564  /*
565  Display minimum, maximum, or mean pixel locations.
566  */
567  statistic_type=(StatisticType) ParseCommandOption(MagickStatisticOptions,
568  MagickFalse,locate);
569  limit=GetImageArtifact(image,"identify:limit");
570  max_locations=0;
571  if (limit != (const char *) NULL)
572  max_locations=StringToUnsignedLong(limit);
573  channel_statistics=GetLocationStatistics(image,statistic_type,exception);
574  if (channel_statistics == (ChannelStatistics *) NULL)
575  return(MagickFalse);
576  (void) FormatLocaleFile(file," Channel %s locations:\n",locate);
577  switch (colorspace)
578  {
579  case RGBColorspace:
580  default:
581  {
582  (void) PrintChannelLocations(file,image,RedChannel,"Red",
583  statistic_type,max_locations,channel_statistics);
584  (void) PrintChannelLocations(file,image,GreenChannel,"Green",
585  statistic_type,max_locations,channel_statistics);
586  (void) PrintChannelLocations(file,image,BlueChannel,"Blue",
587  statistic_type,max_locations,channel_statistics);
588  break;
589  }
590  case CMYKColorspace:
591  {
592  (void) PrintChannelLocations(file,image,CyanChannel,"Cyan",
593  statistic_type,max_locations,channel_statistics);
594  (void) PrintChannelLocations(file,image,MagentaChannel,"Magenta",
595  statistic_type,max_locations,channel_statistics);
596  (void) PrintChannelLocations(file,image,YellowChannel,"Yellow",
597  statistic_type,max_locations,channel_statistics);
598  (void) PrintChannelLocations(file,image,BlackChannel,"Black",
599  statistic_type,max_locations,channel_statistics);
600  break;
601  }
602  case LinearGRAYColorspace:
603  case GRAYColorspace:
604  {
605  (void) PrintChannelLocations(file,image,GrayChannel,"Gray",
606  statistic_type,max_locations,channel_statistics);
607  break;
608  }
609  }
610  if (image->matte != MagickFalse)
611  (void) PrintChannelLocations(file,image,AlphaChannel,"Alpha",
612  statistic_type,max_locations,channel_statistics);
613  channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
614  channel_statistics);
615  exception=DestroyExceptionInfo(exception);
616  return(ferror(file) != 0 ? MagickFalse : MagickTrue);
617  }
618  *format='\0';
619  elapsed_time=GetElapsedTime(&image->timer);
620  user_time=GetUserTime(&image->timer);
621  GetTimerInfo(&image->timer);
622  if (verbose == MagickFalse)
623  {
624  /*
625  Display summary info about the image.
626  */
627  if (*image->magick_filename != '\0')
628  if (LocaleCompare(image->magick_filename,image->filename) != 0)
629  (void) FormatLocaleFile(file,"%s=>",image->magick_filename);
630  if ((GetPreviousImageInList(image) == (Image *) NULL) &&
631  (GetNextImageInList(image) == (Image *) NULL) && (image->scene == 0))
632  (void) FormatLocaleFile(file,"%s ",image->filename);
633  else
634  (void) FormatLocaleFile(file,"%s[%.20g] ",image->filename,(double)
635  image->scene);
636  (void) FormatLocaleFile(file,"%s ",image->magick);
637  if ((image->magick_columns != 0) || (image->magick_rows != 0))
638  if ((image->magick_columns != image->columns) ||
639  (image->magick_rows != image->rows))
640  (void) FormatLocaleFile(file,"%.20gx%.20g=>",(double)
641  image->magick_columns,(double) image->magick_rows);
642  (void) FormatLocaleFile(file,"%.20gx%.20g ",(double) image->columns,
643  (double) image->rows);
644  if ((image->page.width != 0) || (image->page.height != 0) ||
645  (image->page.x != 0) || (image->page.y != 0))
646  (void) FormatLocaleFile(file,"%.20gx%.20g%+.20g%+.20g ",(double)
647  image->page.width,(double) image->page.height,(double) image->page.x,
648  (double) image->page.y);
649  (void) FormatLocaleFile(file,"%.20g-bit ",(double) image->depth);
650  if (image->type != UndefinedType)
651  (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic(
652  MagickTypeOptions,(ssize_t) image->type));
653  if (colorspace != UndefinedColorspace)
654  (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic(
655  MagickColorspaceOptions,(ssize_t) colorspace));
656  if (image->storage_class == DirectClass)
657  {
658  if (image->total_colors != 0)
659  {
660  (void) FormatMagickSize(image->total_colors,MagickFalse,format);
661  (void) FormatLocaleFile(file,"%s ",format);
662  }
663  }
664  else
665  if (image->total_colors <= image->colors)
666  (void) FormatLocaleFile(file,"%.20gc ",(double) image->colors);
667  else
668  (void) FormatLocaleFile(file,"%.20g=>%.20gc ",(double)
669  image->total_colors,(double) image->colors);
670  if (image->error.mean_error_per_pixel != 0.0)
671  (void) FormatLocaleFile(file,"%.20g/%f/%fdb ",(double)
672  (image->error.mean_error_per_pixel+0.5),
673  image->error.normalized_mean_error,
674  image->error.normalized_maximum_error);
675  if (image->extent != 0)
676  {
677  (void) FormatMagickSize(image->extent,MagickTrue,format);
678  (void) FormatLocaleFile(file,"%s ",format);
679  }
680  (void) FormatLocaleFile(file,"%0.3fu %lu:%02lu.%03lu",user_time,
681  (unsigned long) (elapsed_time/60.0),(unsigned long) floor(fmod(
682  elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-
683  floor(elapsed_time))));
684  (void) FormatLocaleFile(file,"\n");
685  (void) fflush(file);
686  exception=DestroyExceptionInfo(exception);
687  return(ferror(file) != 0 ? MagickFalse : MagickTrue);
688  }
689  /*
690  Display verbose info about the image.
691  */
692  pixels=GetVirtualPixels(image,0,0,1,1,exception);
693  exception=DestroyExceptionInfo(exception);
694  ping=pixels == (const PixelPacket *) NULL ? MagickTrue : MagickFalse;
695  exception=(&image->exception);
696  (void) SignatureImage(image);
697  channel_statistics=(ChannelStatistics *) NULL;
698  channel_moments=(ChannelMoments *) NULL;
699  channel_phash=(ChannelPerceptualHash *) NULL;
700  channel_features=(ChannelFeatures *) NULL;
701  depth=0;
702  if (ping == MagickFalse)
703  {
704  depth=GetImageDepth(image,exception);
705  channel_statistics=GetImageChannelStatistics(image,exception);
706  if (channel_statistics == (ChannelStatistics *) NULL)
707  return(MagickFalse);
708  artifact=GetImageArtifact(image,"identify:moments");
709  if (artifact != (const char *) NULL)
710  {
711  channel_moments=GetImageChannelMoments(image,exception);
712  channel_phash=GetImageChannelPerceptualHash(image,exception);
713  }
714  artifact=GetImageArtifact(image,"identify:features");
715  if (artifact != (const char *) NULL)
716  {
717  distance=StringToUnsignedLong(artifact);
718  channel_features=GetImageChannelFeatures(image,distance,exception);
719  }
720  }
721  (void) FormatLocaleFile(file,"Image:\n Filename: %s\n",image->filename);
722  if (*image->magick_filename != '\0')
723  if (LocaleCompare(image->magick_filename,image->filename) != 0)
724  {
725  char
726  filename[MaxTextExtent];
727 
728  GetPathComponent(image->magick_filename,TailPath,filename);
729  (void) FormatLocaleFile(file," Base filename: %s\n",filename);
730  }
731  properties=(*GetBlobProperties(image));
732  if (properties.st_mode != 0)
733  {
734  static const char *rwx[] =
735  { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
736  (void) FormatLocaleFile(file," Permissions: %s%s%s\n",
737  rwx[(properties.st_mode >> 6) & 0x07],
738  rwx[(properties.st_mode >> 3) & 0x07],
739  rwx[(properties.st_mode >> 0) & 0x07]);
740  }
741  magick_info=GetMagickInfo(image->magick,exception);
742  if ((magick_info == (const MagickInfo *) NULL) ||
743  (GetMagickDescription(magick_info) == (const char *) NULL))
744  (void) FormatLocaleFile(file," Format: %s\n",image->magick);
745  else
746  (void) FormatLocaleFile(file," Format: %s (%s)\n",image->magick,
747  GetMagickDescription(magick_info));
748  if ((magick_info != (const MagickInfo *) NULL) &&
749  (GetMagickMimeType(magick_info) != (const char *) NULL))
750  (void) FormatLocaleFile(file," Mime type: %s\n",GetMagickMimeType(
751  magick_info));
752  (void) FormatLocaleFile(file," Class: %s\n",CommandOptionToMnemonic(
753  MagickClassOptions,(ssize_t) image->storage_class));
754  (void) FormatLocaleFile(file," Geometry: %.20gx%.20g%+.20g%+.20g\n",(double)
755  image->columns,(double) image->rows,(double) image->tile_offset.x,(double)
756  image->tile_offset.y);
757  if ((image->magick_columns != 0) || (image->magick_rows != 0))
758  if ((image->magick_columns != image->columns) ||
759  (image->magick_rows != image->rows))
760  (void) FormatLocaleFile(file," Base geometry: %.20gx%.20g\n",(double)
761  image->magick_columns,(double) image->magick_rows);
762  if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
763  {
764  (void) FormatLocaleFile(file," Resolution: %gx%g\n",image->x_resolution,
765  image->y_resolution);
766  (void) FormatLocaleFile(file," Print size: %gx%g\n",(double)
767  image->columns/image->x_resolution,(double) image->rows/
768  image->y_resolution);
769  }
770  (void) FormatLocaleFile(file," Units: %s\n",CommandOptionToMnemonic(
771  MagickResolutionOptions,(ssize_t) image->units));
772  (void) FormatLocaleFile(file," Colorspace: %s\n",CommandOptionToMnemonic(
773  MagickColorspaceOptions,(ssize_t) colorspace));
774  type=IdentifyImageType(image,exception);
775  (void) FormatLocaleFile(file," Type: %s\n",CommandOptionToMnemonic(
776  MagickTypeOptions,(ssize_t) type));
777  if (image->type != type)
778  (void) FormatLocaleFile(file," Base type: %s\n",CommandOptionToMnemonic(
779  MagickTypeOptions,(ssize_t) image->type));
780  (void) FormatLocaleFile(file," Endianness: %s\n",CommandOptionToMnemonic(
781  MagickEndianOptions,(ssize_t) image->endian));
782  if (depth != 0)
783  {
784  if (image->depth == depth)
785  (void) FormatLocaleFile(file," Depth: %.20g-bit\n",(double)
786  image->depth);
787  else
788  (void) FormatLocaleFile(file," Depth: %.20g/%.20g-bit\n",(double)
789  image->depth,(double) depth);
790  }
791  if (channel_statistics != (ChannelStatistics *) NULL)
792  {
793  /*
794  Detail channel depth and extrema.
795  */
796  (void) FormatLocaleFile(file," Channel depth:\n");
797  switch (colorspace)
798  {
799  case RGBColorspace:
800  default:
801  {
802  (void) FormatLocaleFile(file," red: %.20g-bit\n",(double)
803  channel_statistics[RedChannel].depth);
804  (void) FormatLocaleFile(file," green: %.20g-bit\n",(double)
805  channel_statistics[GreenChannel].depth);
806  (void) FormatLocaleFile(file," blue: %.20g-bit\n",(double)
807  channel_statistics[BlueChannel].depth);
808  break;
809  }
810  case CMYKColorspace:
811  {
812  (void) FormatLocaleFile(file," cyan: %.20g-bit\n",(double)
813  channel_statistics[CyanChannel].depth);
814  (void) FormatLocaleFile(file," magenta: %.20g-bit\n",(double)
815  channel_statistics[MagentaChannel].depth);
816  (void) FormatLocaleFile(file," yellow: %.20g-bit\n",(double)
817  channel_statistics[YellowChannel].depth);
818  (void) FormatLocaleFile(file," black: %.20g-bit\n",(double)
819  channel_statistics[BlackChannel].depth);
820  break;
821  }
822  case LinearGRAYColorspace:
823  case GRAYColorspace:
824  {
825  (void) FormatLocaleFile(file," gray: %.20g-bit\n",(double)
826  channel_statistics[GrayChannel].depth);
827  break;
828  }
829  }
830  if (image->matte != MagickFalse)
831  (void) FormatLocaleFile(file," alpha: %.20g-bit\n",(double)
832  channel_statistics[OpacityChannel].depth);
833  scale=1.0;
834  if (image->depth <= MAGICKCORE_QUANTUM_DEPTH)
835  scale=(double) QuantumRange/((size_t) QuantumRange >> ((size_t)
836  MAGICKCORE_QUANTUM_DEPTH-image->depth));
837  (void) FormatLocaleFile(file," Channel statistics:\n");
838  (void) FormatLocaleFile(file," Pixels: %.20g\n",(double)
839  image->columns*image->rows);
840  switch (colorspace)
841  {
842  case RGBColorspace:
843  default:
844  {
845  (void) PrintChannelStatistics(file,RedChannel,"Red",1.0/scale,
846  channel_statistics);
847  (void) PrintChannelStatistics(file,GreenChannel,"Green",1.0/scale,
848  channel_statistics);
849  (void) PrintChannelStatistics(file,BlueChannel,"Blue",1.0/scale,
850  channel_statistics);
851  break;
852  }
853  case CMYKColorspace:
854  {
855  (void) PrintChannelStatistics(file,CyanChannel,"Cyan",1.0/scale,
856  channel_statistics);
857  (void) PrintChannelStatistics(file,MagentaChannel,"Magenta",1.0/scale,
858  channel_statistics);
859  (void) PrintChannelStatistics(file,YellowChannel,"Yellow",1.0/scale,
860  channel_statistics);
861  (void) PrintChannelStatistics(file,BlackChannel,"Black",1.0/scale,
862  channel_statistics);
863  break;
864  }
865  case LinearGRAYColorspace:
866  case GRAYColorspace:
867  {
868  (void) PrintChannelStatistics(file,GrayChannel,"Gray",1.0/scale,
869  channel_statistics);
870  break;
871  }
872  }
873  if (image->matte != MagickFalse)
874  (void) PrintChannelStatistics(file,AlphaChannel,"Alpha",1.0/scale,
875  channel_statistics);
876  if ((colorspace != LinearGRAYColorspace) && (colorspace != GRAYColorspace))
877  {
878  (void) FormatLocaleFile(file," Image statistics:\n");
879  (void) PrintChannelStatistics(file,CompositeChannels,"Overall",1.0/
880  scale,channel_statistics);
881  }
882  channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
883  channel_statistics);
884  }
885  if (channel_moments != (ChannelMoments *) NULL)
886  {
887  scale=(double) ((1UL << image->depth)-1);
888  (void) FormatLocaleFile(file," Channel moments:\n");
889  switch (colorspace)
890  {
891  case RGBColorspace:
892  default:
893  {
894  (void) PrintChannelMoments(file,RedChannel,"Red",scale,
895  channel_moments);
896  (void) PrintChannelMoments(file,GreenChannel,"Green",scale,
897  channel_moments);
898  (void) PrintChannelMoments(file,BlueChannel,"Blue",scale,
899  channel_moments);
900  break;
901  }
902  case CMYKColorspace:
903  {
904  (void) PrintChannelMoments(file,CyanChannel,"Cyan",scale,
905  channel_moments);
906  (void) PrintChannelMoments(file,MagentaChannel,"Magenta",scale,
907  channel_moments);
908  (void) PrintChannelMoments(file,YellowChannel,"Yellow",scale,
909  channel_moments);
910  (void) PrintChannelMoments(file,BlackChannel,"Black",scale,
911  channel_moments);
912  break;
913  }
914  case LinearGRAYColorspace:
915  case GRAYColorspace:
916  {
917  (void) PrintChannelMoments(file,GrayChannel,"Gray",scale,
918  channel_moments);
919  break;
920  }
921  }
922  if (image->matte != MagickFalse)
923  (void) PrintChannelMoments(file,AlphaChannel,"Alpha",scale,
924  channel_moments);
925  if ((colorspace != LinearGRAYColorspace) && (colorspace != GRAYColorspace))
926  {
927  (void) FormatLocaleFile(file," Image moments:\n");
928  (void) PrintChannelMoments(file,CompositeChannels,"Overall",scale,
929  channel_moments);
930  }
931  channel_moments=(ChannelMoments *) RelinquishMagickMemory(
932  channel_moments);
933  }
934  if (channel_phash != (ChannelPerceptualHash *) NULL)
935  {
936  (void) FormatLocaleFile(file," Channel perceptual hash:\n");
937  (void) PrintChannelPerceptualHash(file,RedChannel,"Red, Hue",
938  channel_phash);
939  (void) PrintChannelPerceptualHash(file,GreenChannel,"Green, Chroma",
940  channel_phash);
941  (void) PrintChannelPerceptualHash(file,BlueChannel,"Blue, Luma",
942  channel_phash);
943  if (image->matte != MagickFalse)
944  (void) PrintChannelPerceptualHash(file,AlphaChannel,"Alpha, Alpha",
945  channel_phash);
946  channel_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(
947  channel_phash);
948  }
949  if (channel_features != (ChannelFeatures *) NULL)
950  {
951  (void) FormatLocaleFile(file," Channel features (horizontal, vertical, "
952  "left and right diagonals, average):\n");
953  switch (colorspace)
954  {
955  case RGBColorspace:
956  default:
957  {
958  (void) PrintChannelFeatures(file,RedChannel,"Red",channel_features);
959  (void) PrintChannelFeatures(file,GreenChannel,"Green",
960  channel_features);
961  (void) PrintChannelFeatures(file,BlueChannel,"Blue",channel_features);
962  break;
963  }
964  case CMYKColorspace:
965  {
966  (void) PrintChannelFeatures(file,CyanChannel,"Cyan",channel_features);
967  (void) PrintChannelFeatures(file,MagentaChannel,"Magenta",
968  channel_features);
969  (void) PrintChannelFeatures(file,YellowChannel,"Yellow",
970  channel_features);
971  (void) PrintChannelFeatures(file,BlackChannel,"Black",
972  channel_features);
973  break;
974  }
975  case LinearGRAYColorspace:
976  case GRAYColorspace:
977  {
978  (void) PrintChannelFeatures(file,GrayChannel,"Gray",channel_features);
979  break;
980  }
981  }
982  if (image->matte != MagickFalse)
983  (void) PrintChannelFeatures(file,AlphaChannel,"Alpha",channel_features);
984  channel_features=(ChannelFeatures *) RelinquishMagickMemory(
985  channel_features);
986  }
987  if (ping == MagickFalse)
988  {
989  if (colorspace == CMYKColorspace)
990  (void) FormatLocaleFile(file," Total ink density: %.*g%%\n",
991  GetMagickPrecision(),100.0*GetImageTotalInkDensity(image)/(double)
992  QuantumRange);
993  x=0;
994  if (image->matte != MagickFalse)
995  {
996  MagickBooleanType
997  found = MagickFalse;
998 
999  const IndexPacket
1000  *indexes;
1001 
1002  const PixelPacket
1003  *p;
1004 
1005  p=(PixelPacket *) NULL;
1006  indexes=(IndexPacket *) NULL;
1007  for (y=0; y < (ssize_t) image->rows; y++)
1008  {
1009  p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1010  if (p == (const PixelPacket *) NULL)
1011  break;
1012  indexes=GetVirtualIndexQueue(image);
1013  for (x=0; x < (ssize_t) image->columns; x++)
1014  {
1015  if (GetPixelOpacity(p) == (Quantum) TransparentOpacity)
1016  {
1017  found=MagickTrue;
1018  break;
1019  }
1020  p++;
1021  }
1022  if (found != MagickFalse)
1023  break;
1024  }
1025  if (found != MagickFalse)
1026  {
1027  char
1028  tuple[MaxTextExtent];
1029 
1031  pixel;
1032 
1033  GetMagickPixelPacket(image,&pixel);
1034  SetMagickPixelPacket(image,p,indexes+x,&pixel);
1035  (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
1036  exception);
1037  (void) FormatLocaleFile(file," Alpha: %s ",tuple);
1038  GetColorTuple(&pixel,MagickTrue,tuple);
1039  (void) FormatLocaleFile(file," %s\n",tuple);
1040  }
1041  }
1042  artifact=GetImageArtifact(image,"identify:unique-colors");
1043  if (IsHistogramImage(image,exception) != MagickFalse)
1044  {
1045  (void) FormatLocaleFile(file," Colors: %.20g\n",(double)
1046  GetNumberColors(image,(FILE *) NULL,exception));
1047  (void) FormatLocaleFile(file," Histogram:\n");
1048  (void) GetNumberColors(image,file,exception);
1049  }
1050  else
1051  if ((artifact != (const char *) NULL) &&
1052  (IsMagickTrue(artifact) != MagickFalse))
1053  (void) FormatLocaleFile(file," Colors: %.20g\n",(double)
1054  GetNumberColors(image,(FILE *) NULL,exception));
1055  }
1056  if (image->storage_class == PseudoClass)
1057  {
1058  (void) FormatLocaleFile(file," Colormap entries: %.20g\n",(double)
1059  image->colors);
1060  (void) FormatLocaleFile(file," Colormap:\n");
1061  if (image->colors <= 1024)
1062  {
1063  char
1064  color[MaxTextExtent],
1065  hex[MaxTextExtent],
1066  tuple[MaxTextExtent];
1067 
1069  pixel;
1070 
1071  PixelPacket
1072  *magick_restrict p;
1073 
1074  GetMagickPixelPacket(image,&pixel);
1075  p=image->colormap;
1076  for (i=0; i < (ssize_t) image->colors; i++)
1077  {
1078  SetMagickPixelPacket(image,p,(IndexPacket *) NULL,&pixel);
1079  (void) CopyMagickString(tuple,"(",MaxTextExtent);
1080  ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
1081  (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1082  ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
1083  (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1084  ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
1085  if (pixel.colorspace == CMYKColorspace)
1086  {
1087  (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1088  ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,
1089  tuple);
1090  }
1091  if (pixel.matte != MagickFalse)
1092  {
1093  (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
1094  ConcatenateColorComponent(&pixel,AlphaChannel,X11Compliance,
1095  tuple);
1096  }
1097  (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
1098  (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,
1099  exception);
1100  GetColorTuple(&pixel,MagickTrue,hex);
1101  (void) FormatLocaleFile(file," %g: %s %s %s\n",(double) i,tuple,
1102  hex,color);
1103  p++;
1104  }
1105  }
1106  }
1107  if (image->error.mean_error_per_pixel != 0.0)
1108  (void) FormatLocaleFile(file," Mean error per pixel: %g\n",
1109  image->error.mean_error_per_pixel);
1110  if (image->error.normalized_mean_error != 0.0)
1111  (void) FormatLocaleFile(file," Normalized mean error: %g\n",
1112  image->error.normalized_mean_error);
1113  if (image->error.normalized_maximum_error != 0.0)
1114  (void) FormatLocaleFile(file," Normalized maximum error: %g\n",
1115  image->error.normalized_maximum_error);
1116  (void) FormatLocaleFile(file," Rendering intent: %s\n",
1117  CommandOptionToMnemonic(MagickIntentOptions,(ssize_t)
1118  image->rendering_intent));
1119  if (image->gamma != 0.0)
1120  (void) FormatLocaleFile(file," Gamma: %g\n",image->gamma);
1121  if ((image->chromaticity.red_primary.x != 0.0) ||
1122  (image->chromaticity.green_primary.x != 0.0) ||
1123  (image->chromaticity.blue_primary.x != 0.0) ||
1124  (image->chromaticity.white_point.x != 0.0))
1125  {
1126  /*
1127  Display image chromaticity.
1128  */
1129  (void) FormatLocaleFile(file," Chromaticity:\n");
1130  (void) FormatLocaleFile(file," red primary: (%g,%g,%g)\n",
1131  image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1132  image->chromaticity.red_primary.z);
1133  (void) FormatLocaleFile(file," green primary: (%g,%g,%g)\n",
1134  image->chromaticity.green_primary.x,image->chromaticity.green_primary.y,
1135  image->chromaticity.green_primary.z);
1136  (void) FormatLocaleFile(file," blue primary: (%g,%g,%g)\n",
1137  image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y,
1138  image->chromaticity.blue_primary.z);
1139  (void) FormatLocaleFile(file," white point: (%g,%g,%g)\n",
1140  image->chromaticity.white_point.x,image->chromaticity.white_point.y,
1141  image->chromaticity.white_point.z);
1142  }
1143  if ((image->extract_info.width*image->extract_info.height) != 0)
1144  (void) FormatLocaleFile(file," Tile geometry: %.20gx%.20g%+.20g%+.20g\n",
1145  (double) image->extract_info.width,(double) image->extract_info.height,
1146  (double) image->extract_info.x,(double) image->extract_info.y);
1147  (void) QueryColorname(image,&image->background_color,SVGCompliance,color,
1148  exception);
1149  (void) FormatLocaleFile(file," Background color: %s\n",color);
1150  (void) QueryColorname(image,&image->border_color,SVGCompliance,color,
1151  exception);
1152  (void) FormatLocaleFile(file," Border color: %s\n",color);
1153  (void) QueryColorname(image,&image->matte_color,SVGCompliance,color,
1154  exception);
1155  (void) FormatLocaleFile(file," Matte color: %s\n",color);
1156  (void) QueryColorname(image,&image->transparent_color,SVGCompliance,color,
1157  exception);
1158  (void) FormatLocaleFile(file," Transparent color: %s\n",color);
1159  (void) FormatLocaleFile(file," Interlace: %s\n",CommandOptionToMnemonic(
1160  MagickInterlaceOptions,(ssize_t) image->interlace));
1161  (void) FormatLocaleFile(file," Intensity: %s\n",CommandOptionToMnemonic(
1162  MagickPixelIntensityOptions,(ssize_t) image->intensity));
1163  (void) FormatLocaleFile(file," Compose: %s\n",CommandOptionToMnemonic(
1164  MagickComposeOptions,(ssize_t) image->compose));
1165  if ((image->page.width != 0) || (image->page.height != 0) ||
1166  (image->page.x != 0) || (image->page.y != 0))
1167  (void) FormatLocaleFile(file," Page geometry: %.20gx%.20g%+.20g%+.20g\n",
1168  (double) image->page.width,(double) image->page.height,(double)
1169  image->page.x,(double) image->page.y);
1170  if ((image->page.x != 0) || (image->page.y != 0))
1171  (void) FormatLocaleFile(file," Origin geometry: %+.20g%+.20g\n",(double)
1172  image->page.x,(double) image->page.y);
1173  (void) FormatLocaleFile(file," Dispose: %s\n",CommandOptionToMnemonic(
1174  MagickDisposeOptions,(ssize_t) image->dispose));
1175  if (image->delay != 0)
1176  (void) FormatLocaleFile(file," Delay: %.20gx%.20g\n",(double) image->delay,
1177  (double) image->ticks_per_second);
1178  if (image->iterations != 1)
1179  (void) FormatLocaleFile(file," Iterations: %.20g\n",(double)
1180  image->iterations);
1181  if (image->duration != 0)
1182  (void) FormatLocaleFile(file," Duration: %.20g\n",(double)
1183  image->duration);
1184  if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
1185  (void) FormatLocaleFile(file," Scene: %.20g of %.20g\n",(double)
1186  image->scene,(double) GetImageListLength(image));
1187  else
1188  if (image->scene != 0)
1189  (void) FormatLocaleFile(file," Scene: %.20g\n",(double) image->scene);
1190  (void) FormatLocaleFile(file," Compression: %s\n",CommandOptionToMnemonic(
1191  MagickCompressOptions,(ssize_t) image->compression));
1192  if (image->quality != UndefinedCompressionQuality)
1193  (void) FormatLocaleFile(file," Quality: %.20g\n",(double) image->quality);
1194  (void) FormatLocaleFile(file," Orientation: %s\n",CommandOptionToMnemonic(
1195  MagickOrientationOptions,(ssize_t) image->orientation));
1196  if (image->montage != (char *) NULL)
1197  (void) FormatLocaleFile(file," Montage: %s\n",image->montage);
1198  if (image->directory != (char *) NULL)
1199  {
1200  Image
1201  *tile;
1202 
1203  ImageInfo
1204  *image_info;
1205 
1206  char
1207  *p,
1208  *q;
1209 
1210  WarningHandler
1211  handler;
1212 
1213  /*
1214  Display visual image directory.
1215  */
1216  image_info=AcquireImageInfo();
1217  (void) CloneString(&image_info->size,"64x64");
1218  (void) FormatLocaleFile(file," Directory:\n");
1219  for (p=image->directory; *p != '\0'; p++)
1220  {
1221  q=p;
1222  while ((*q != '\xff') && (*q != '\0') &&
1223  ((size_t) (q-p) < sizeof(image_info->filename)))
1224  q++;
1225  (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1));
1226  p=q;
1227  (void) FormatLocaleFile(file," %s",image_info->filename);
1228  handler=SetWarningHandler((WarningHandler) NULL);
1229  tile=ReadImage(image_info,exception);
1230  (void) SetWarningHandler(handler);
1231  if (tile == (Image *) NULL)
1232  {
1233  (void) FormatLocaleFile(file,"\n");
1234  continue;
1235  }
1236  (void) FormatLocaleFile(file," %.20gx%.20g %s\n",(double)
1237  tile->magick_columns,(double) tile->magick_rows,tile->magick);
1238  (void) SignatureImage(tile);
1239  ResetImagePropertyIterator(tile);
1240  property=GetNextImageProperty(tile);
1241  while (property != (const char *) NULL)
1242  {
1243  (void) FormatLocaleFile(file," %s:\n",property);
1244  value=GetImageProperty(tile,property);
1245  if (value != (const char *) NULL)
1246  (void) FormatLocaleFile(file,"%s\n",value);
1247  property=GetNextImageProperty(tile);
1248  }
1249  tile=DestroyImage(tile);
1250  }
1251  image_info=DestroyImageInfo(image_info);
1252  }
1253  (void) FormatLocaleString(key,MaxTextExtent,"8BIM:1999,2998:#1");
1254  value=GetImageProperty(image,key);
1255  if (value != (const char *) NULL)
1256  {
1257  /*
1258  Display clipping path.
1259  */
1260  (void) FormatLocaleFile(file," Clipping path: ");
1261  if (strlen(value) > 80)
1262  (void) fputc('\n',file);
1263  (void) FormatLocaleFile(file,"%s\n",value);
1264  }
1265  ResetImageProfileIterator(image);
1266  name=GetNextImageProfile(image);
1267  if (name != (char *) NULL)
1268  {
1269  const StringInfo
1270  *profile;
1271 
1272  /*
1273  Identify image profiles.
1274  */
1275  (void) FormatLocaleFile(file," Profiles:\n");
1276  while (name != (char *) NULL)
1277  {
1278  profile=GetImageProfile(image,name);
1279  if (profile == (StringInfo *) NULL)
1280  continue;
1281  (void) FormatLocaleFile(file," Profile-%s: %.20g bytes\n",name,
1282  (double) GetStringInfoLength(profile));
1283  if (LocaleCompare(name,"iptc") == 0)
1284  {
1285  char
1286  *attribute,
1287  **attribute_list;
1288 
1289  const char
1290  *tag;
1291 
1292  long
1293  dataset,
1294  record,
1295  sentinel;
1296 
1297  ssize_t
1298  j;
1299 
1300  size_t
1301  length,
1302  profile_length;
1303 
1304  profile_length=GetStringInfoLength(profile);
1305  for (i=0; i < (ssize_t) profile_length-5; i+=(ssize_t) length)
1306  {
1307  length=1;
1308  sentinel=GetStringInfoDatum(profile)[i++];
1309  if (sentinel != 0x1c)
1310  continue;
1311  dataset=GetStringInfoDatum(profile)[i++];
1312  record=GetStringInfoDatum(profile)[i++];
1313  switch (record)
1314  {
1315  case 5: tag="Image Name"; break;
1316  case 7: tag="Edit Status"; break;
1317  case 10: tag="Priority"; break;
1318  case 15: tag="Category"; break;
1319  case 20: tag="Supplemental Category"; break;
1320  case 22: tag="Fixture Identifier"; break;
1321  case 25: tag="Keyword"; break;
1322  case 30: tag="Release Date"; break;
1323  case 35: tag="Release Time"; break;
1324  case 40: tag="Special Instructions"; break;
1325  case 45: tag="Reference Service"; break;
1326  case 47: tag="Reference Date"; break;
1327  case 50: tag="Reference Number"; break;
1328  case 55: tag="Created Date"; break;
1329  case 60: tag="Created Time"; break;
1330  case 65: tag="Originating Program"; break;
1331  case 70: tag="Program Version"; break;
1332  case 75: tag="Object Cycle"; break;
1333  case 80: tag="Byline"; break;
1334  case 85: tag="Byline Title"; break;
1335  case 90: tag="City"; break;
1336  case 92: tag="Sub-Location"; break;
1337  case 95: tag="Province State"; break;
1338  case 100: tag="Country Code"; break;
1339  case 101: tag="Country"; break;
1340  case 103: tag="Original Transmission Reference"; break;
1341  case 105: tag="Headline"; break;
1342  case 110: tag="Credit"; break;
1343  case 115: tag="Src"; break;
1344  case 116: tag="Copyright String"; break;
1345  case 120: tag="Caption"; break;
1346  case 121: tag="Local Caption"; break;
1347  case 122: tag="Caption Writer"; break;
1348  case 200: tag="Custom Field 1"; break;
1349  case 201: tag="Custom Field 2"; break;
1350  case 202: tag="Custom Field 3"; break;
1351  case 203: tag="Custom Field 4"; break;
1352  case 204: tag="Custom Field 5"; break;
1353  case 205: tag="Custom Field 6"; break;
1354  case 206: tag="Custom Field 7"; break;
1355  case 207: tag="Custom Field 8"; break;
1356  case 208: tag="Custom Field 9"; break;
1357  case 209: tag="Custom Field 10"; break;
1358  case 210: tag="Custom Field 11"; break;
1359  case 211: tag="Custom Field 12"; break;
1360  case 212: tag="Custom Field 13"; break;
1361  case 213: tag="Custom Field 14"; break;
1362  case 214: tag="Custom Field 15"; break;
1363  case 215: tag="Custom Field 16"; break;
1364  case 216: tag="Custom Field 17"; break;
1365  case 217: tag="Custom Field 18"; break;
1366  case 218: tag="Custom Field 19"; break;
1367  case 219: tag="Custom Field 20"; break;
1368  default: tag="unknown"; break;
1369  }
1370  (void) FormatLocaleFile(file," %s[%.20g,%.20g]: ",tag,
1371  (double) dataset,(double) record);
1372  length=(size_t) (GetStringInfoDatum(profile)[i++] << 8);
1373  length|=GetStringInfoDatum(profile)[i++];
1374  length=MagickMin(length,profile_length-i);
1375  attribute=(char *) NULL;
1376  if (~length >= (MaxTextExtent-1))
1377  attribute=(char *) AcquireQuantumMemory(length+
1378  MaxTextExtent,sizeof(*attribute));
1379  if (attribute != (char *) NULL)
1380  {
1381  (void) CopyMagickString(attribute,(char *)
1382  GetStringInfoDatum(profile)+i,length+1);
1383  attribute_list=StringToList(attribute);
1384  if (attribute_list != (char **) NULL)
1385  {
1386  for (j=0; attribute_list[j] != (char *) NULL; j++)
1387  {
1388  (void) fputs(attribute_list[j],file);
1389  (void) fputs("\n",file);
1390  attribute_list[j]=(char *) RelinquishMagickMemory(
1391  attribute_list[j]);
1392  }
1393  attribute_list=(char **) RelinquishMagickMemory(
1394  attribute_list);
1395  }
1396  attribute=DestroyString(attribute);
1397  }
1398  }
1399  }
1400  if (image->debug != MagickFalse)
1401  PrintStringInfo(file,name,profile);
1402  name=GetNextImageProfile(image);
1403  }
1404  }
1405  ResetImagePropertyIterator(image);
1406  property=GetNextImageProperty(image);
1407  if (property != (const char *) NULL)
1408  {
1409  /*
1410  Display image properties.
1411  */
1412  (void) FormatLocaleFile(file," Properties:\n");
1413  while (property != (const char *) NULL)
1414  {
1415  (void) FormatLocaleFile(file," %s: ",property);
1416  value=GetImageProperty(image,property);
1417  if (value != (const char *) NULL)
1418  (void) FormatLocaleFile(file,"%s\n",value);
1419  property=GetNextImageProperty(image);
1420  }
1421  }
1422  ResetImageArtifactIterator(image);
1423  artifact=GetNextImageArtifact(image);
1424  if (artifact != (const char *) NULL)
1425  {
1426  /*
1427  Display image artifacts.
1428  */
1429  (void) FormatLocaleFile(file," Artifacts:\n");
1430  while (artifact != (const char *) NULL)
1431  {
1432  (void) FormatLocaleFile(file," %s: ",artifact);
1433  value=GetImageArtifact(image,artifact);
1434  if (value != (const char *) NULL)
1435  (void) FormatLocaleFile(file,"%s\n",value);
1436  artifact=GetNextImageArtifact(image);
1437  }
1438  }
1439  ResetImageRegistryIterator();
1440  registry=GetNextImageRegistry();
1441  if (registry != (const char *) NULL)
1442  {
1443  /*
1444  Display image registry.
1445  */
1446  (void) FormatLocaleFile(file," Registry:\n");
1447  while (registry != (const char *) NULL)
1448  {
1449  (void) FormatLocaleFile(file," %s: ",registry);
1450  value=(const char *) GetImageRegistry(StringRegistryType,registry,
1451  exception);
1452  if (value != (const char *) NULL)
1453  (void) FormatLocaleFile(file,"%s\n",value);
1454  registry=GetNextImageRegistry();
1455  }
1456  }
1457  (void) FormatLocaleFile(file," Tainted: %s\n",CommandOptionToMnemonic(
1458  MagickBooleanOptions,(ssize_t) image->taint));
1459  (void) FormatMagickSize(image->extent,MagickTrue,format);
1460  (void) FormatLocaleFile(file," Filesize: %s\n",format);
1461  (void) FormatMagickSize((MagickSizeType) image->columns*image->rows,
1462  MagickFalse,format);
1463  if (strlen(format) > 1)
1464  format[strlen(format)-1]='\0';
1465  (void) FormatLocaleFile(file," Number pixels: %s\n",format);
1466  if (elapsed_time > MagickEpsilon)
1467  {
1468  (void) FormatMagickSize((MagickSizeType) ((double) image->columns*
1469  image->rows/elapsed_time+0.5),MagickFalse,format);
1470  (void) FormatLocaleFile(file," Pixels per second: %s\n",format);
1471  }
1472  if (image->ttl != (time_t) 0)
1473  {
1474  char
1475  iso8601[sizeof("9999-99-99T99:99:99Z")];
1476 
1477  int
1478  seconds;
1479 
1480  struct tm
1481  timestamp;
1482 
1483  (void) GetMagickUTCTime(&image->ttl,&timestamp);
1484  (void) strftime(iso8601,sizeof(iso8601),"%Y-%m-%dT%H:%M:%SZ",&timestamp);
1485  seconds=MagickMax((int)(image->ttl-GetMagickTime()),0);
1486  expired=' ';
1487  if (seconds == 0)
1488  expired='*';
1489  (void) FormatLocaleFile(file," Time-to-live: %g:%02g:%02g:%02g%c %s\n",
1490  ceil((double) (seconds/(3600*24))),
1491  ceil((double) ((seconds % (24*3600))/3600)),
1492  ceil((double) ((seconds % 3600)/60)),
1493  ceil((double) ((seconds % 3600) % 60)),expired,iso8601);
1494  }
1495  (void) FormatLocaleFile(file," User time: %0.3fu\n",user_time);
1496  (void) FormatLocaleFile(file," Elapsed time: %lu:%02lu.%03lu\n",
1497  (unsigned long) (elapsed_time/60.0),(unsigned long) ceil(fmod(
1498  elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-floor(
1499  elapsed_time))));
1500  (void) FormatLocaleFile(file," Version: %s\n",GetMagickVersion((size_t *)
1501  NULL));
1502  (void) fflush(file);
1503  return(ferror(file) != 0 ? MagickFalse : MagickTrue);
1504 }
Definition: image.h:134