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