1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                        Y   Y   AAA   M   M  L                               %
7 %                         Y Y   A   A  MM MM  L                               %
8 %                          Y    AAAAA  M M M  L                               %
9 %                          Y    A   A  M   M  L                               %
10 %                          Y    A   A  M   M  LLLLL                           %
11 %                                                                             %
12 %                                                                             %
13 %                  Write Info About the Image in YAML Format.                 %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                January 2014                                 %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/artifact.h"
44 #include "MagickCore/attribute.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/blob-private.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/colorspace.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/feature.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/pixel-private.h"
65 #include "MagickCore/prepress.h"
66 #include "MagickCore/property.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/registry.h"
69 #include "MagickCore/signature.h"
70 #include "MagickCore/static.h"
71 #include "MagickCore/statistic.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/string-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/version.h"
76 #include "MagickCore/module.h"
77 
78 /*
79   Typedef declarations.
80 */
81 typedef struct _IPTCInfo
82 {
83   long
84     dataset,
85     record;
86 
87   size_t
88     values_length;
89 
90   char
91     tag[32],
92     ***values;
93 } IPTCInfo;
94 
95 /*
96   Forward declarations.
97 */
98 static MagickBooleanType
99   WriteYAMLImage(const ImageInfo *,Image *,ExceptionInfo *);
100 
101 /*
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 %                                                                             %
104 %                                                                             %
105 %                                                                             %
106 %   R e g i s t e r Y A M L I m a g e                                         %
107 %                                                                             %
108 %                                                                             %
109 %                                                                             %
110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111 %
112 %  RegisterYAMLImage() adds attributes for the YAML image format to
113 %  the list of supported formats.  The attributes include the image format
114 %  tag, a method to read and/or write the format, whether the format
115 %  supports the saving of more than one frame to the same file or blob,
116 %  whether the format supports native in-memory I/O, and a brief
117 %  description of the format.
118 %
119 %  The format of the RegisterYAMLImage method is:
120 %
121 %      size_t RegisterYAMLImage(void)
122 %
123 */
RegisterYAMLImage(void)124 ModuleExport size_t RegisterYAMLImage(void)
125 {
126   MagickInfo
127     *entry;
128 
129   entry=AcquireMagickInfo("YAML","YAML","The image format and characteristics");
130   entry->encoder=(EncodeImageHandler *) WriteYAMLImage;
131   entry->mime_type=ConstantString("application/json");
132   entry->flags|=CoderEndianSupportFlag;
133   entry->flags^=CoderBlobSupportFlag;
134   (void) RegisterMagickInfo(entry);
135   return(MagickImageCoderSignature);
136 }
137 
138 /*
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 %                                                                             %
141 %                                                                             %
142 %                                                                             %
143 %   U n r e g i s t e r Y A M L I m a g e                                     %
144 %                                                                             %
145 %                                                                             %
146 %                                                                             %
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 %
149 %  UnregisterYAMLImage() removes format registrations made by the
150 %  YAML module from the list of supported formats.
151 %
152 %  The format of the UnregisterYAMLImage method is:
153 %
154 %      UnregisterYAMLImage(void)
155 %
156 */
UnregisterYAMLImage(void)157 ModuleExport void UnregisterYAMLImage(void)
158 {
159   (void) UnregisterMagickInfo("YAML");
160 }
161 
162 /*
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 %                                                                             %
165 %                                                                             %
166 %                                                                             %
167 %   W r i t e Y A M L I m a g e                                               %
168 %                                                                             %
169 %                                                                             %
170 %                                                                             %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 %
173 %  WriteYAMLImage writes the image attributes in the YAML format.
174 %
175 %  The format of the WriteYAMLImage method is:
176 %
177 %      MagickBooleanType WriteYAMLImage(const ImageInfo *image_info,
178 %        Image *image,ExceptionInfo *exception)
179 %
180 %  A description of each parameter follows.
181 %
182 %    o image_info: the image info.
183 %
184 %    o image:  The image.
185 %
186 %    o exception: return any errors or warnings in this structure.
187 %
188 */
189 
YAMLFormatLocaleFile(FILE * file,const char * format,const char * value)190 static void YAMLFormatLocaleFile(FILE *file,const char *format,
191   const char *value)
192 {
193   char
194     *escaped_json;
195 
196   char
197     *q;
198 
199   const char
200     *p;
201 
202   size_t
203     length;
204 
205   assert(format != (const char *) NULL);
206   if ((value == (char *) NULL) || (*value == '\0'))
207     {
208       (void) FormatLocaleFile(file,format,"null");
209       return;
210     }
211   length=strlen(value)+2;
212   /*
213     Find all the chars that need escaping and increase the dest length counter.
214   */
215   for (p=value; *p != '\0'; p++)
216   {
217     switch (*p)
218     {
219       case '"':
220       case '\b':
221       case '\f':
222       case '\n':
223       case '\r':
224       case '\t':
225       case '\\':
226       {
227         if (~length < 1)
228           return;
229         length++;
230         break;
231       }
232       default:
233       {
234         if (((int) *p >= 0x00) && ((int) *p <= 0x1f))
235           length+=6;
236         break;
237       }
238     }
239   }
240   escaped_json=(char *) NULL;
241   if (~length >= (MagickPathExtent-1))
242     escaped_json=(char *) AcquireQuantumMemory(length+MagickPathExtent,
243       sizeof(*escaped_json));
244   if (escaped_json == (char *) NULL)
245     {
246       (void) FormatLocaleFile(file,format,"null");
247       return;
248     }
249   q=escaped_json;
250   if (strchr(value,':') != (char *) NULL)
251     *q++='"';
252   for (p=value; *p != '\0'; p++)
253   {
254     switch (*p)
255     {
256       case '"':
257       {
258         *q++='\\';
259         *q++=(*p);
260         break;
261       }
262       case '\b':
263       {
264         *q++='\\';
265         *q++='b';
266         break;
267       }
268       case '\f':
269       {
270         *q++='\\';
271         *q++='f';
272         break;
273       }
274       case '\n':
275       {
276         *q++='\\';
277         *q++='n';
278         break;
279       }
280       case '\r':
281       {
282         *q++='\\';
283         *q++='r';
284         break;
285       }
286       case '\t':
287       {
288         *q++='\\';
289         *q++='t';
290         break;
291       }
292       case '\\':
293       {
294         *q++='\\';
295         *q++='\\';
296         break;
297       }
298       default:
299       {
300         if (((int) *p >= 0x00) && ((int) *p <= 0x1f))
301           {
302             (void) FormatLocaleString(q,7,"\\u%04X",(int) *p);
303             q+=6;
304             break;
305           }
306         *q++=(*p);
307         break;
308       }
309     }
310   }
311   if (strchr(value,':') != (char *) NULL)
312     *q++='"';
313   *q='\0';
314   (void) FormatLocaleFile(file,format,escaped_json);
315   (void) DestroyString(escaped_json);
316 }
317 
GetLocationStatistics(const Image * image,const StatisticType type,ExceptionInfo * exception)318 static ChannelStatistics *GetLocationStatistics(const Image *image,
319   const StatisticType type,ExceptionInfo *exception)
320 {
321   ChannelStatistics
322     *channel_statistics;
323 
324   ssize_t
325     i;
326 
327   ssize_t
328     y;
329 
330   assert(image != (Image *) NULL);
331   assert(image->signature == MagickCoreSignature);
332   if (image->debug != MagickFalse)
333     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
334   channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
335     MaxPixelChannels+1,sizeof(*channel_statistics));
336   if (channel_statistics == (ChannelStatistics *) NULL)
337     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
338   (void) memset(channel_statistics,0,(MaxPixelChannels+1)*
339     sizeof(*channel_statistics));
340   for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
341   {
342     switch (type)
343     {
344       case MaximumStatistic:
345       default:
346       {
347         channel_statistics[i].maxima=(-MagickMaximumValue);
348         break;
349       }
350       case MinimumStatistic:
351       {
352         channel_statistics[i].minima=MagickMaximumValue;
353         break;
354       }
355     }
356   }
357   for (y=0; y < (ssize_t) image->rows; y++)
358   {
359     const Quantum
360       *magick_restrict p;
361 
362     ssize_t
363       x;
364 
365     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
366     if (p == (const Quantum *) NULL)
367       break;
368     for (x=0; x < (ssize_t) image->columns; x++)
369     {
370       ssize_t
371         i;
372 
373       if (GetPixelReadMask(image,p) <= (QuantumRange/2))
374         {
375           p+=GetPixelChannels(image);
376           continue;
377         }
378       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
379       {
380         PixelChannel channel = GetPixelChannelChannel(image,i);
381         PixelTrait traits = GetPixelChannelTraits(image,channel);
382         if (traits == UndefinedPixelTrait)
383           continue;
384         switch (type)
385         {
386           case MaximumStatistic:
387           default:
388           {
389             if ((double) p[i] > channel_statistics[channel].maxima)
390               channel_statistics[channel].maxima=(double) p[i];
391             break;
392           }
393           case MinimumStatistic:
394           {
395             if ((double) p[i] < channel_statistics[channel].minima)
396               channel_statistics[channel].minima=(double) p[i];
397             break;
398           }
399         }
400       }
401       p+=GetPixelChannels(image);
402     }
403   }
404   return(channel_statistics);
405 }
406 
PrintChannelFeatures(FILE * file,const PixelChannel channel,const char * name,const MagickBooleanType separator,const ChannelFeatures * channel_features)407 static ssize_t PrintChannelFeatures(FILE *file,const PixelChannel channel,
408   const char *name,const MagickBooleanType separator,
409   const ChannelFeatures *channel_features)
410 {
411 #define PrintFeature(feature) \
412   GetMagickPrecision(),(feature)[0], \
413   GetMagickPrecision(),(feature)[1], \
414   GetMagickPrecision(),(feature)[2], \
415   GetMagickPrecision(),(feature)[3], \
416   GetMagickPrecision(),((feature)[0]+(feature)[1]+(feature)[2]+(feature)[3])/4.0 \
417 
418 #define FeaturesFormat "      %s: \n" \
419   "        angularSecondMoment: \n" \
420   "          horizontal: %.*g\n" \
421   "          vertical: %.*g\n" \
422   "          leftDiagonal: %.*g\n" \
423   "          rightDiagonal: %.*g\n" \
424   "          average: %.*g\n" \
425   "        \n" \
426   "        contrast: \n" \
427   "          horizontal: %.*g\n" \
428   "          vertical: %.*g\n" \
429   "          leftDiagonal: %.*g\n" \
430   "          rightDiagonal: %.*g\n" \
431   "          average: %.*g\n" \
432   "        \n" \
433   "        correlation: \n" \
434   "          horizontal: %.*g\n" \
435   "          vertical: %.*g\n" \
436   "          leftDiagonal: %.*g\n" \
437   "          rightDiagonal: %.*g\n" \
438   "          average: %.*g\n" \
439   "        \n" \
440   "        sumOfSquaresVariance: \n" \
441   "          horizontal: %.*g\n" \
442   "          vertical: %.*g\n" \
443   "          leftDiagonal: %.*g\n" \
444   "          rightDiagonal: %.*g\n" \
445   "          average: %.*g\n" \
446   "        \n" \
447   "        inverseDifferenceMoment: \n" \
448   "          horizontal: %.*g\n" \
449   "          vertical: %.*g\n" \
450   "          leftDiagonal: %.*g\n" \
451   "          rightDiagonal: %.*g\n" \
452   "          average: %.*g\n" \
453   "        \n" \
454   "        sumAverage: \n" \
455   "          horizontal: %.*g\n" \
456   "          vertical: %.*g\n" \
457   "          leftDiagonal: %.*g\n" \
458   "          rightDiagonal: %.*g\n" \
459   "          average: %.*g\n" \
460   "        \n" \
461   "        sumVariance: \n" \
462   "          horizontal: %.*g\n" \
463   "          vertical: %.*g\n" \
464   "          leftDiagonal: %.*g\n" \
465   "          rightDiagonal: %.*g\n" \
466   "          average: %.*g\n" \
467   "        \n" \
468   "        sumEntropy: \n" \
469   "          horizontal: %.*g\n" \
470   "          vertical: %.*g\n" \
471   "          leftDiagonal: %.*g\n" \
472   "          rightDiagonal: %.*g\n" \
473   "          average: %.*g\n" \
474   "        \n" \
475   "        entropy: \n" \
476   "          horizontal: %.*g\n" \
477   "          vertical: %.*g\n" \
478   "          leftDiagonal: %.*g\n" \
479   "          rightDiagonal: %.*g\n" \
480   "          average: %.*g\n" \
481   "        \n" \
482   "        differenceVariance: \n" \
483   "          horizontal: %.*g\n" \
484   "          vertical: %.*g\n" \
485   "          leftDiagonal: %.*g\n" \
486   "          rightDiagonal: %.*g\n" \
487   "          average: %.*g\n" \
488   "        \n" \
489   "        differenceEntropy: \n" \
490   "          horizontal: %.*g\n" \
491   "          vertical: %.*g\n" \
492   "          leftDiagonal: %.*g\n" \
493   "          rightDiagonal: %.*g\n" \
494   "          average: %.*g\n" \
495   "        \n" \
496   "        informationMeasureOfCorrelation1: \n" \
497   "          horizontal: %.*g\n" \
498   "          vertical: %.*g\n" \
499   "          leftDiagonal: %.*g\n" \
500   "          rightDiagonal: %.*g\n" \
501   "          average: %.*g\n" \
502   "        \n" \
503   "        informationMeasureOfCorrelation2: \n" \
504   "          horizontal: %.*g\n" \
505   "          vertical: %.*g\n" \
506   "          leftDiagonal: %.*g\n" \
507   "          rightDiagonal: %.*g\n" \
508   "          average: %.*g\n" \
509   "        \n" \
510   "        maximumCorrelationCoefficient: \n" \
511   "          horizontal: %.*g\n" \
512   "          vertical: %.*g\n" \
513   "          leftDiagonal: %.*g\n" \
514   "          rightDiagonal: %.*g\n" \
515   "          average: %.*g\n" \
516   "        \n"
517 
518   ssize_t
519     n;
520 
521   n=FormatLocaleFile(file,FeaturesFormat,name,
522     PrintFeature(channel_features[channel].angular_second_moment),
523     PrintFeature(channel_features[channel].contrast),
524     PrintFeature(channel_features[channel].correlation),
525     PrintFeature(channel_features[channel].variance_sum_of_squares),
526     PrintFeature(channel_features[channel].inverse_difference_moment),
527     PrintFeature(channel_features[channel].sum_average),
528     PrintFeature(channel_features[channel].sum_variance),
529     PrintFeature(channel_features[channel].sum_entropy),
530     PrintFeature(channel_features[channel].entropy),
531     PrintFeature(channel_features[channel].difference_variance),
532     PrintFeature(channel_features[channel].difference_entropy),
533     PrintFeature(channel_features[channel].measure_of_correlation_1),
534     PrintFeature(channel_features[channel].measure_of_correlation_2),
535     PrintFeature(channel_features[channel].maximum_correlation_coefficient));
536   (void) FormatLocaleFile(file,"      ");
537   if (separator != MagickFalse)
538     (void) FormatLocaleFile(file," ");
539   (void) FormatLocaleFile(file,"\n");
540   return(n);
541 }
542 
PrintChannelLocations(FILE * file,const Image * image,const PixelChannel channel,const char * name,const StatisticType type,const size_t max_locations,const MagickBooleanType separator,const ChannelStatistics * channel_statistics)543 static ssize_t PrintChannelLocations(FILE *file,const Image *image,
544   const PixelChannel channel,const char *name,const StatisticType type,
545   const size_t max_locations,const MagickBooleanType separator,
546   const ChannelStatistics *channel_statistics)
547 {
548   double
549     target;
550 
551   ExceptionInfo
552     *exception;
553 
554   ssize_t
555     n,
556     y;
557 
558   switch (type)
559   {
560     case MaximumStatistic:
561     default:
562     {
563       target=channel_statistics[channel].maxima;
564       break;
565     }
566     case MinimumStatistic:
567     {
568       target=channel_statistics[channel].minima;
569       break;
570     }
571   }
572   (void) FormatLocaleFile(file,"      %s: \n        intensity: "
573     "%.*g\n",name,GetMagickPrecision(),QuantumScale*target);
574   exception=AcquireExceptionInfo();
575   n=0;
576   for (y=0; y < (ssize_t) image->rows; y++)
577   {
578     const Quantum
579       *p;
580 
581     ssize_t
582       offset,
583       x;
584 
585     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
586     if (p == (const Quantum *) NULL)
587       break;
588     for (x=0; x < (ssize_t) image->columns; x++)
589     {
590       MagickBooleanType
591         match;
592 
593       PixelTrait traits = GetPixelChannelTraits(image,channel);
594       if (traits == UndefinedPixelTrait)
595         continue;
596       offset=GetPixelChannelOffset(image,channel);
597       match=fabs((double) (p[offset]-target)) < 0.5 ? MagickTrue : MagickFalse;
598       if (match != MagickFalse)
599         {
600           if ((max_locations != 0) && (n >= (ssize_t) max_locations))
601             break;
602           if (n != 0)
603             (void) FormatLocaleFile(file,"\n");
604           (void) FormatLocaleFile(file,"        location%.20g: \n"
605             "          x: %.20g\n          y: %.20g\n"
606             "        ",(double) n,(double) x,(double) y);
607           n++;
608         }
609       p+=GetPixelChannels(image);
610     }
611     if (x < (ssize_t) image->columns)
612       break;
613   }
614   (void) FormatLocaleFile(file,"\n      ");
615   if (separator != MagickFalse)
616     (void) FormatLocaleFile(file," ");
617   (void) FormatLocaleFile(file,"\n");
618   return(n);
619 }
620 
PrintChannelMoments(FILE * file,const PixelChannel channel,const char * name,const MagickBooleanType separator,const ChannelMoments * channel_moments)621 static ssize_t PrintChannelMoments(FILE *file,const PixelChannel channel,
622   const char *name,const MagickBooleanType separator,
623   const ChannelMoments *channel_moments)
624 {
625   ssize_t
626     i;
627 
628   ssize_t
629     n;
630 
631   n=FormatLocaleFile(file,"      %s: \n",name);
632   n+=FormatLocaleFile(file,"        centroid: \n "
633     "          x: %.*g\n"
634     "           y: %.*g\n        \n",
635     GetMagickPrecision(),channel_moments[channel].centroid.x,
636     GetMagickPrecision(),channel_moments[channel].centroid.y);
637   n+=FormatLocaleFile(file,"        ellipseSemiMajorMinorAxis: \n"
638     "          x: %.*g\n"
639     "          y: %.*g\n        \n",
640     GetMagickPrecision(),channel_moments[channel].ellipse_axis.x,
641     GetMagickPrecision(),channel_moments[channel].ellipse_axis.y);
642   n+=FormatLocaleFile(file,"        ellipseAngle: %.*g\n",
643     GetMagickPrecision(),channel_moments[channel].ellipse_angle);
644   n+=FormatLocaleFile(file,"        ellipseEccentricity: %.*g\n",
645     GetMagickPrecision(),channel_moments[channel].ellipse_eccentricity);
646   n+=FormatLocaleFile(file,"        ellipseIntensity: %.*g\n",
647     GetMagickPrecision(),channel_moments[channel].ellipse_intensity);
648   for (i=0; i < 7; i++)
649     n+=FormatLocaleFile(file,"        I%.20g: %.*g\n",i+1.0,
650       GetMagickPrecision(),channel_moments[channel].invariant[i]);
651   n+=FormatLocaleFile(file,"        I%.20g: %.*g\n",i+1.0,
652     GetMagickPrecision(),channel_moments[channel].invariant[i]);
653   (void) FormatLocaleFile(file,"      ");
654   if (separator != MagickFalse)
655     (void) FormatLocaleFile(file," ");
656   (void) FormatLocaleFile(file,"\n");
657   return(n);
658 }
659 
PrintChannelPerceptualHash(Image * image,FILE * file,const ChannelPerceptualHash * channel_phash)660 static ssize_t PrintChannelPerceptualHash(Image *image,FILE *file,
661   const ChannelPerceptualHash *channel_phash)
662 {
663   ssize_t
664     i;
665 
666   ssize_t
667     n = 0;
668 
669   (void) FormatLocaleFile(file,"      colorspaces:  ");
670   for (i=0; i < (ssize_t) channel_phash[0].number_colorspaces; i++)
671   {
672     (void) FormatLocaleFile(file,"- %s",CommandOptionToMnemonic(
673       MagickColorspaceOptions,(ssize_t) channel_phash[0].colorspace[i]));
674   }
675   (void) FormatLocaleFile(file,"\n");
676   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
677   {
678     ssize_t
679       j;
680 
681     PixelChannel channel = GetPixelChannelChannel(image,i);
682     PixelTrait traits = GetPixelChannelTraits(image,channel);
683     if (traits == UndefinedPixelTrait)
684       continue;
685     n=FormatLocaleFile(file,"      Channel%.20g: \n",(double) channel);
686     for (j=0; j < MaximumNumberOfPerceptualHashes; j++)
687     {
688       ssize_t
689         k;
690 
691       n+=FormatLocaleFile(file,"        PH%.20g: ",(double) j+1);
692       for (k=0; k < (ssize_t) channel_phash[0].number_colorspaces; k++)
693       {
694         n+=FormatLocaleFile(file,"- %.*g",GetMagickPrecision(),
695           channel_phash[channel].phash[k][j]);
696       }
697       n+=FormatLocaleFile(file," ");
698       if (j < (MaximumNumberOfPerceptualHashes-1))
699         n+=FormatLocaleFile(file,"\n");
700     }
701     if (i < (ssize_t) (GetPixelChannels(image)-1))
702       n+=FormatLocaleFile(file,"\n      \n");
703   }
704   n+=FormatLocaleFile(file,"\n      \n");
705   return(n);
706 }
707 
PrintChannelStatistics(FILE * file,const PixelChannel channel,const char * name,const double scale,const MagickBooleanType separator,const ChannelStatistics * channel_statistics)708 static ssize_t PrintChannelStatistics(FILE *file,const PixelChannel channel,
709   const char *name,const double scale,const MagickBooleanType separator,
710   const ChannelStatistics *channel_statistics)
711 {
712 #define StatisticsFormat "      %s: \n        min: %.*g\n"  \
713   "        max: %.*g\n        mean: %.*g\n        median: %.*g\n        "  \
714   "standardDeviation: %.*g\n        kurtosis: %.*g\n        "\
715   "skewness: %.*g\n        entropy: %.*g\n      "
716 
717   ssize_t
718     n;
719 
720   n=FormatLocaleFile(file,StatisticsFormat,name,GetMagickPrecision(),
721     (double) ClampToQuantum(scale*channel_statistics[channel].minima),
722     GetMagickPrecision(),(double) ClampToQuantum(scale*
723     channel_statistics[channel].maxima),GetMagickPrecision(),
724     scale*channel_statistics[channel].mean,GetMagickPrecision(),
725     scale*channel_statistics[channel].median,GetMagickPrecision(),
726     IsNaN(channel_statistics[channel].standard_deviation) != 0 ? MagickEpsilon :
727     scale*channel_statistics[channel].standard_deviation,GetMagickPrecision(),
728     channel_statistics[channel].kurtosis,GetMagickPrecision(),
729     channel_statistics[channel].skewness,GetMagickPrecision(),
730     channel_statistics[channel].entropy);
731   if (separator != MagickFalse)
732     (void) FormatLocaleFile(file," ");
733   (void) FormatLocaleFile(file,"\n");
734   return(n);
735 }
736 
EncodeIptcProfile(FILE * file,const StringInfo * profile)737 static void EncodeIptcProfile(FILE *file,const StringInfo *profile)
738 {
739   char
740     *attribute,
741     **attribute_list;
742 
743   const char
744     *tag;
745 
746   IPTCInfo
747     *value,
748     **values;
749 
750   long
751     dataset,
752     record,
753     sentinel;
754 
755   ssize_t
756     i,
757     j,
758     k;
759 
760   size_t
761     count,
762     length,
763     profile_length;
764 
765   values=(IPTCInfo **) NULL;
766   count=0;
767   profile_length=GetStringInfoLength(profile);
768   for (i=0; i < (ssize_t) profile_length; i+=(ssize_t) length)
769   {
770     length=1;
771     sentinel=GetStringInfoDatum(profile)[i++];
772     if (sentinel != 0x1c)
773       continue;
774     dataset=GetStringInfoDatum(profile)[i++];
775     record=GetStringInfoDatum(profile)[i++];
776     value=(IPTCInfo *) NULL;
777     for (j=0; j < (ssize_t) count; j++)
778     {
779       if ((values[j]->record == record) && (values[j]->dataset == dataset))
780         value=values[j];
781     }
782     if (value == (IPTCInfo *) NULL)
783       {
784         values=(IPTCInfo **) ResizeQuantumMemory(values,count+1,
785           sizeof(*values));
786         if (values == (IPTCInfo **) NULL)
787           break;
788         value=(IPTCInfo *) AcquireMagickMemory(sizeof(*value));
789         if (value == (IPTCInfo *) NULL)
790           break;
791         /* Check the tag length in IPTCInfo when a new tag is added */
792         switch (record)
793         {
794           case 5: tag="Image Name"; break;
795           case 7: tag="Edit Status"; break;
796           case 10: tag="Priority"; break;
797           case 15: tag="Category"; break;
798           case 20: tag="Supplemental Category"; break;
799           case 22: tag="Fixture Identifier"; break;
800           case 25: tag="Keyword"; break;
801           case 30: tag="Release Date"; break;
802           case 35: tag="Release Time"; break;
803           case 40: tag="Special Instructions"; break;
804           case 45: tag="Reference Service"; break;
805           case 47: tag="Reference Date"; break;
806           case 50: tag="Reference Number"; break;
807           case 55: tag="Created Date"; break;
808           case 60: tag="Created Time"; break;
809           case 65: tag="Originating Program"; break;
810           case 70: tag="Program Version"; break;
811           case 75: tag="Object Cycle"; break;
812           case 80: tag="Byline"; break;
813           case 85: tag="Byline Title"; break;
814           case 90: tag="City"; break;
815           case 92: tag="Sub-Location"; break;
816           case 95: tag="Province State"; break;
817           case 100: tag="Country Code"; break;
818           case 101: tag="Country"; break;
819           case 103: tag="Original Transmission Reference"; break;
820           case 105: tag="Headline"; break;
821           case 110: tag="Credit"; break;
822           case 115: tag="Src"; break;
823           case 116: tag="Copyright String"; break;
824           case 120: tag="Caption"; break;
825           case 121: tag="Local Caption"; break;
826           case 122: tag="Caption Writer"; break;
827           case 200: tag="Custom Field 1"; break;
828           case 201: tag="Custom Field 2"; break;
829           case 202: tag="Custom Field 3"; break;
830           case 203: tag="Custom Field 4"; break;
831           case 204: tag="Custom Field 5"; break;
832           case 205: tag="Custom Field 6"; break;
833           case 206: tag="Custom Field 7"; break;
834           case 207: tag="Custom Field 8"; break;
835           case 208: tag="Custom Field 9"; break;
836           case 209: tag="Custom Field 10"; break;
837           case 210: tag="Custom Field 11"; break;
838           case 211: tag="Custom Field 12"; break;
839           case 212: tag="Custom Field 13"; break;
840           case 213: tag="Custom Field 14"; break;
841           case 214: tag="Custom Field 15"; break;
842           case 215: tag="Custom Field 16"; break;
843           case 216: tag="Custom Field 17"; break;
844           case 217: tag="Custom Field 18"; break;
845           case 218: tag="Custom Field 19"; break;
846           case 219: tag="Custom Field 20"; break;
847           default: tag="Unknown"; break;
848         }
849         (void) CopyMagickString(value->tag,tag,strlen(tag)+1);
850         value->record=record;
851         value->dataset=dataset;
852         value->values=(char ***) NULL;
853         value->values_length=0;
854         values[count++]=value;
855       }
856     length=(size_t) (GetStringInfoDatum(profile)[i++] << 8);
857     length|=GetStringInfoDatum(profile)[i++];
858     attribute=(char *) NULL;
859     if (~length >= (MagickPathExtent-1))
860       attribute=(char *) AcquireQuantumMemory(length+MagickPathExtent,
861         sizeof(*attribute));
862     if (attribute != (char *) NULL)
863       {
864         (void) CopyMagickString(attribute,(char *)
865           GetStringInfoDatum(profile)+i,length+1);
866         attribute_list=StringToList(attribute);
867         if (attribute_list != (char **) NULL)
868           {
869             value->values=(char ***) ResizeQuantumMemory(value->values,
870               value->values_length+1,
871               sizeof(*value->values));
872             if (value->values == (char ***) NULL)
873               break;
874             value->values[value->values_length++]=attribute_list;
875           }
876         attribute=DestroyString(attribute);
877       }
878   }
879   if (values != (IPTCInfo **) NULL)
880     {
881       for (i=0; i < (ssize_t) count; i++)
882       {
883         value=values[i];
884         (void) FormatLocaleFile(file,"        %s[%.20g,%.20g]: ",
885           value->tag,(double) value->dataset,(double) value->record);
886         if (value->values_length == 0)
887           (void) FormatLocaleFile(file,"null,");
888         else
889           {
890             (void) FormatLocaleFile(file,"[");
891             for (j=0; j < (ssize_t) value->values_length; j++)
892             {
893               for (k=0; value->values[j][k] != (char *) NULL; k++)
894               {
895                 if (j > 0 || k > 0)
896                   (void) FormatLocaleFile(file," ");
897                 YAMLFormatLocaleFile(file,"%s",value->values[j][k]);
898                 value->values[j][k]=(char *) RelinquishMagickMemory(
899                   value->values[j][k]);
900               }
901               value->values[j]=(char **) RelinquishMagickMemory(
902                 value->values[j]);
903             }
904             value->values=(char ***) RelinquishMagickMemory(value->values);
905             (void) FormatLocaleFile(file,"]\n");
906           }
907         values[i]=(IPTCInfo *) RelinquishMagickMemory(values[i]);
908       }
909       values=(IPTCInfo **) RelinquishMagickMemory(values);
910     }
911 }
912 
EncodeImageAttributes(Image * image,FILE * file,ExceptionInfo * exception)913 static MagickBooleanType EncodeImageAttributes(Image *image,FILE *file,
914   ExceptionInfo *exception)
915 {
916   char
917     color[MagickPathExtent],
918     format[MagickPathExtent],
919     key[MagickPathExtent];
920 
921   ChannelFeatures
922     *channel_features;
923 
924   ChannelMoments
925     *channel_moments;
926 
927   ChannelPerceptualHash
928     *channel_phash;
929 
930   ChannelStatistics
931     *channel_statistics;
932 
933   const char
934     *artifact,
935     *locate,
936     *name,
937     *property,
938     *registry,
939     *value;
940 
941   const MagickInfo
942     *magick_info;
943 
944   double
945     elapsed_time,
946     user_time,
947     version;
948 
949   ImageType
950     type;
951 
952   MagickBooleanType
953     ping;
954 
955   const Quantum
956     *p;
957 
958   ssize_t
959     i,
960     x;
961 
962   size_t
963     depth,
964     distance,
965     scale;
966 
967   ssize_t
968     y;
969 
970   assert(image != (Image *) NULL);
971   assert(image->signature == MagickCoreSignature);
972   if (image->debug != MagickFalse)
973     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
974   *format='\0';
975   elapsed_time=GetElapsedTime(&image->timer);
976   user_time=GetUserTime(&image->timer);
977   GetTimerInfo(&image->timer);
978   p=GetVirtualPixels(image,0,0,1,1,exception);
979   ping=p == (const Quantum *) NULL ? MagickTrue : MagickFalse;
980   (void) ping;
981   (void) SignatureImage(image,exception);
982   (void) FormatLocaleFile(file,"---\n");
983   version=1.0;
984   artifact=GetImageArtifact(image,"yaml:version");
985   if (artifact != (const char *) NULL)
986     version=StringToDouble(artifact,(char **) NULL);
987   if (version >= 1.0)
988     (void) FormatLocaleFile(file,"  version: %.1f\n",version);
989   if (*image->magick_filename == '\0')
990     YAMLFormatLocaleFile(file,"  image: \n    name: %s\n",
991       image->filename);
992   else
993     {
994       YAMLFormatLocaleFile(file,"  image: \n    name: %s\n",
995         image->magick_filename);
996       if (LocaleCompare(image->magick_filename,image->filename) != 0)
997         {
998           char
999             filename[MagickPathExtent];
1000 
1001           GetPathComponent(image->magick_filename,TailPath,filename);
1002           YAMLFormatLocaleFile(file,"    baseName: %s\n",filename);
1003         }
1004     }
1005   YAMLFormatLocaleFile(file,"    format: %s\n",image->magick);
1006   magick_info=GetMagickInfo(image->magick,exception);
1007   if ((magick_info != (const MagickInfo *) NULL) &&
1008       (GetMagickDescription(magick_info) != (const char *) NULL))
1009     YAMLFormatLocaleFile(file,"    formatDescription: %s\n",
1010       image->magick);
1011   if ((magick_info != (const MagickInfo *) NULL) &&
1012       (GetMagickMimeType(magick_info) != (const char *) NULL))
1013     YAMLFormatLocaleFile(file,"    mimeType: %s\n",GetMagickMimeType(
1014       magick_info));
1015   YAMLFormatLocaleFile(file,"    class: %s\n",CommandOptionToMnemonic(
1016     MagickClassOptions,(ssize_t) image->storage_class));
1017   (void) FormatLocaleFile(file,"    geometry: \n"
1018     "      width: %g\n      height: %g\n"
1019     "      x: %g\n      y: %g\n    \n",
1020     (double) image->columns,(double) image->rows,(double) image->tile_offset.x,
1021     (double) image->tile_offset.y);
1022   if ((image->magick_columns != 0) || (image->magick_rows != 0))
1023     if ((image->magick_columns != image->columns) ||
1024         (image->magick_rows != image->rows))
1025       (void) FormatLocaleFile(file,"    baseGeometry: \n"
1026         "      width: %g\n      height: %g\n    \n",(double)
1027         image->magick_columns,(double) image->magick_rows);
1028   if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
1029     {
1030       (void) FormatLocaleFile(file,"    resolution: \n"
1031         "      x: %g\n      y: %g\n    \n",image->resolution.x,
1032         image->resolution.y);
1033       (void) FormatLocaleFile(file,"    printSize: \n"
1034         "      x: %.*g\n      y: %.*g\n    \n",GetMagickPrecision(),
1035         image->columns/image->resolution.x,GetMagickPrecision(),(double)
1036         image->rows/image->resolution.y);
1037     }
1038   YAMLFormatLocaleFile(file,"    units: %s\n",CommandOptionToMnemonic(
1039     MagickResolutionOptions,(ssize_t) image->units));
1040   type=IdentifyImageType(image,exception);
1041   YAMLFormatLocaleFile(file,"    type: %s\n",CommandOptionToMnemonic(
1042     MagickTypeOptions,(ssize_t) type));
1043   if (image->type != type)
1044     YAMLFormatLocaleFile(file,"    baseType: %s\n",
1045       CommandOptionToMnemonic(MagickTypeOptions,(ssize_t) image->type));
1046   if (version < 1.0)
1047     YAMLFormatLocaleFile(file,"    endianess: %s\n",
1048       CommandOptionToMnemonic(MagickEndianOptions,(ssize_t) image->endian));
1049   else
1050     YAMLFormatLocaleFile(file,"    endianness: %s\n",
1051       CommandOptionToMnemonic(MagickEndianOptions,(ssize_t) image->endian));
1052   locate=GetImageArtifact(image,"identify:locate");
1053   if (locate == (const char *) NULL)
1054     locate=GetImageArtifact(image,"yaml:locate");
1055   if (locate != (const char *) NULL)
1056     {
1057       const char
1058         *limit;
1059 
1060       size_t
1061         max_locations;
1062 
1063       StatisticType
1064         type;
1065 
1066       /*
1067         Display minimum, maximum, or mean pixel locations.
1068       */
1069       type=(StatisticType) ParseCommandOption(MagickStatisticOptions,
1070         MagickFalse,locate);
1071       limit=GetImageArtifact(image,"identify:limit");
1072       if (limit == (const char *) NULL)
1073         limit=GetImageArtifact(image,"yaml:limit");
1074       max_locations=0;
1075       if (limit != (const char *) NULL)
1076         max_locations=StringToUnsignedLong(limit);
1077       channel_statistics=GetLocationStatistics(image,type,exception);
1078       if (channel_statistics == (ChannelStatistics *) NULL)
1079         return(MagickFalse);
1080       (void) FormatLocaleFile(file,"    channel%s: \n",locate);
1081       if (image->alpha_trait != UndefinedPixelTrait)
1082         (void) PrintChannelLocations(file,image,AlphaPixelChannel,"alpha",
1083           type,max_locations,MagickTrue,channel_statistics);
1084       switch (image->colorspace)
1085       {
1086         case RGBColorspace:
1087         default:
1088         {
1089           (void) PrintChannelLocations(file,image,RedPixelChannel,"red",
1090             type,max_locations,MagickTrue,channel_statistics);
1091           (void) PrintChannelLocations(file,image,GreenPixelChannel,"green",
1092             type,max_locations,MagickTrue,channel_statistics);
1093           (void) PrintChannelLocations(file,image,BluePixelChannel,"blue",
1094             type,max_locations,MagickFalse,channel_statistics);
1095           break;
1096         }
1097         case CMYKColorspace:
1098         {
1099           (void) PrintChannelLocations(file,image,CyanPixelChannel,"cyan",
1100             type,max_locations,MagickTrue,channel_statistics);
1101           (void) PrintChannelLocations(file,image,MagentaPixelChannel,
1102             "magenta",type,max_locations,MagickTrue,channel_statistics);
1103           (void) PrintChannelLocations(file,image,YellowPixelChannel,"yellow",
1104             type,max_locations,MagickTrue,channel_statistics);
1105           (void) PrintChannelLocations(file,image,BlackPixelChannel,"black",
1106             type,max_locations,MagickFalse,channel_statistics);
1107           break;
1108         }
1109         case LinearGRAYColorspace:
1110         case GRAYColorspace:
1111         {
1112           (void) PrintChannelLocations(file,image,GrayPixelChannel,"gray",
1113             type,max_locations,MagickFalse,channel_statistics);
1114           break;
1115         }
1116       }
1117       (void) FormatLocaleFile(file,"    \n");
1118       channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1119         channel_statistics);
1120     }
1121   /*
1122     Detail channel depth and extrema.
1123   */
1124   YAMLFormatLocaleFile(file,"    colorspace: %s\n",
1125     CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t)
1126     image->colorspace));
1127   channel_statistics=(ChannelStatistics *) NULL;
1128   channel_moments=(ChannelMoments *) NULL;
1129   channel_phash=(ChannelPerceptualHash *) NULL;
1130   channel_features=(ChannelFeatures *) NULL;
1131   scale=1;
1132   channel_statistics=GetImageStatistics(image,exception);
1133   if (channel_statistics == (ChannelStatistics *) NULL)
1134     return(MagickFalse);
1135   artifact=GetImageArtifact(image,"identify:moments");
1136   if (artifact == (const char *) NULL)
1137     artifact=GetImageArtifact(image,"yaml:moments");
1138   if (artifact != (const char *) NULL)
1139     {
1140       channel_moments=GetImageMoments(image,exception);
1141       channel_phash=GetImagePerceptualHash(image,exception);
1142     }
1143   artifact=GetImageArtifact(image,"identify:features");
1144   if (artifact == (const char *) NULL)
1145     artifact=GetImageArtifact(image,"yaml:features");
1146   if (artifact != (const char *) NULL)
1147     {
1148       distance=StringToUnsignedLong(artifact);
1149       channel_features=GetImageFeatures(image,distance,exception);
1150     }
1151   depth=GetImageDepth(image,exception);
1152   (void) FormatLocaleFile(file,"    depth: %g\n",(double) depth);
1153   (void) FormatLocaleFile(file,"    baseDepth: %g\n",(double)
1154     image->depth);
1155   (void) FormatLocaleFile(file,"    channelDepth: \n");
1156   if (image->alpha_trait != UndefinedPixelTrait)
1157     (void) FormatLocaleFile(file,"      alpha: %.20g\n",(double)
1158       channel_statistics[AlphaPixelChannel].depth);
1159   switch (image->colorspace)
1160   {
1161     case RGBColorspace:
1162     default:
1163     {
1164       (void) FormatLocaleFile(file,"      red: %.20g\n",(double)
1165         channel_statistics[RedChannel].depth);
1166       (void) FormatLocaleFile(file,"      green: %.20g\n",(double)
1167         channel_statistics[GreenChannel].depth);
1168       (void) FormatLocaleFile(file,"      blue: %.20g\n",(double)
1169         channel_statistics[BlueChannel].depth);
1170       break;
1171     }
1172     case CMYKColorspace:
1173     {
1174       (void) FormatLocaleFile(file,"      cyan: %.20g\n",(double)
1175         channel_statistics[CyanChannel].depth);
1176       (void) FormatLocaleFile(file,"      magenta: %.20g\n",(double)
1177         channel_statistics[MagentaChannel].depth);
1178       (void) FormatLocaleFile(file,"      yellow: %.20g\n",(double)
1179         channel_statistics[YellowChannel].depth);
1180       (void) FormatLocaleFile(file,"      black: %.20g\n",(double)
1181         channel_statistics[BlackChannel].depth);
1182       break;
1183     }
1184     case LinearGRAYColorspace:
1185     case GRAYColorspace:
1186     {
1187       (void) FormatLocaleFile(file,"      gray: %.20g\n",(double)
1188         channel_statistics[GrayChannel].depth);
1189       break;
1190     }
1191   }
1192   (void) FormatLocaleFile(file,"    \n");
1193   scale=1;
1194   if (image->depth <= MAGICKCORE_QUANTUM_DEPTH)
1195     scale=QuantumRange/((size_t) QuantumRange >> ((size_t)
1196       MAGICKCORE_QUANTUM_DEPTH-image->depth));
1197   if (channel_statistics != (ChannelStatistics *) NULL)
1198     {
1199       (void) FormatLocaleFile(file,"    pixels: %.20g\n",
1200         channel_statistics[CompositePixelChannel].area);
1201       if ((image->colorspace != LinearGRAYColorspace) &&
1202           (image->colorspace != GRAYColorspace))
1203         {
1204           (void) FormatLocaleFile(file,"    imageStatistics: \n");
1205           (void) PrintChannelStatistics(file,(PixelChannel) MaxPixelChannels,
1206             "overall",1.0/scale,MagickFalse,channel_statistics);
1207           (void) FormatLocaleFile(file,"    \n");
1208         }
1209       (void) FormatLocaleFile(file,"    channelStatistics: \n");
1210       if (image->alpha_trait != UndefinedPixelTrait)
1211         (void) PrintChannelStatistics(file,AlphaPixelChannel,"alpha",1.0/scale,
1212           MagickTrue,channel_statistics);
1213       switch (image->colorspace)
1214       {
1215         case RGBColorspace:
1216         default:
1217         {
1218           (void) PrintChannelStatistics(file,RedPixelChannel,"red",1.0/scale,
1219             MagickTrue,channel_statistics);
1220           (void) PrintChannelStatistics(file,GreenPixelChannel,"green",1.0/
1221             scale,MagickTrue,channel_statistics);
1222           (void) PrintChannelStatistics(file,BluePixelChannel,"blue",1.0/scale,
1223             MagickFalse,channel_statistics);
1224           break;
1225         }
1226         case CMYKColorspace:
1227         {
1228           (void) PrintChannelStatistics(file,CyanPixelChannel,"cyan",1.0/scale,
1229             MagickTrue,channel_statistics);
1230           (void) PrintChannelStatistics(file,MagentaPixelChannel,"magenta",1.0/
1231             scale,MagickTrue,channel_statistics);
1232           (void) PrintChannelStatistics(file,YellowPixelChannel,"yellow",1.0/
1233             scale,MagickTrue,channel_statistics);
1234           (void) PrintChannelStatistics(file,BlackPixelChannel,"black",1.0/
1235             scale,MagickFalse,channel_statistics);
1236           break;
1237         }
1238         case LinearGRAYColorspace:
1239         case GRAYColorspace:
1240         {
1241           (void) PrintChannelStatistics(file,GrayPixelChannel,"gray",1.0/scale,
1242             MagickFalse,channel_statistics);
1243           break;
1244         }
1245       }
1246       (void) FormatLocaleFile(file,"    \n");
1247       channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1248         channel_statistics);
1249     }
1250   if (channel_moments != (ChannelMoments *) NULL)
1251     {
1252       (void) FormatLocaleFile(file,"    channelMoments: \n");
1253       if (image->alpha_trait != UndefinedPixelTrait)
1254         (void) PrintChannelMoments(file,AlphaPixelChannel,"alpha",MagickTrue,
1255           channel_moments);
1256       switch (image->colorspace)
1257       {
1258         case RGBColorspace:
1259         default:
1260         {
1261           (void) PrintChannelMoments(file,RedPixelChannel,"red",MagickTrue,
1262             channel_moments);
1263           (void) PrintChannelMoments(file,GreenPixelChannel,"green",MagickTrue,
1264             channel_moments);
1265           (void) PrintChannelMoments(file,BluePixelChannel,"blue",MagickFalse,
1266             channel_moments);
1267           break;
1268         }
1269         case CMYKColorspace:
1270         {
1271           (void) PrintChannelMoments(file,CyanPixelChannel,"cyan",MagickTrue,
1272             channel_moments);
1273           (void) PrintChannelMoments(file,MagentaPixelChannel,"magenta",
1274             MagickTrue,channel_moments);
1275           (void) PrintChannelMoments(file,YellowPixelChannel,"yellow",
1276             MagickTrue,channel_moments);
1277           (void) PrintChannelMoments(file,BlackPixelChannel,"black",
1278             MagickFalse,channel_moments);
1279           break;
1280         }
1281         case LinearGRAYColorspace:
1282         case GRAYColorspace:
1283         {
1284           (void) PrintChannelMoments(file,GrayPixelChannel,"gray",MagickFalse,
1285             channel_moments);
1286           break;
1287         }
1288       }
1289       (void) FormatLocaleFile(file,"    \n");
1290       channel_moments=(ChannelMoments *) RelinquishMagickMemory(
1291         channel_moments);
1292     }
1293   if (channel_phash != (ChannelPerceptualHash *) NULL)
1294     {
1295       (void) FormatLocaleFile(file,"    channelPerceptualHash: \n");
1296       (void) PrintChannelPerceptualHash(image,file,channel_phash);
1297       (void) FormatLocaleFile(file,"    \n");
1298       channel_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(
1299         channel_phash);
1300     }
1301   if (channel_features != (ChannelFeatures *) NULL)
1302     {
1303       (void) FormatLocaleFile(file,"    channelFeatures: \n");
1304       if (image->alpha_trait != UndefinedPixelTrait)
1305         (void) PrintChannelFeatures(file,AlphaPixelChannel,"alpha",MagickTrue,
1306           channel_features);
1307       switch (image->colorspace)
1308       {
1309         case RGBColorspace:
1310         default:
1311         {
1312           (void) PrintChannelFeatures(file,RedPixelChannel,"red",MagickTrue,
1313             channel_features);
1314           (void) PrintChannelFeatures(file,GreenPixelChannel,"green",
1315             MagickTrue,channel_features);
1316           (void) PrintChannelFeatures(file,BluePixelChannel,"blue",MagickFalse,
1317             channel_features);
1318           break;
1319         }
1320         case CMYKColorspace:
1321         {
1322           (void) PrintChannelFeatures(file,CyanPixelChannel,"cyan",MagickTrue,
1323             channel_features);
1324           (void) PrintChannelFeatures(file,MagentaPixelChannel,"magenta",
1325             MagickTrue,channel_features);
1326           (void) PrintChannelFeatures(file,YellowPixelChannel,"yellow",
1327             MagickTrue,channel_features);
1328           (void) PrintChannelFeatures(file,BlackPixelChannel,"black",
1329             MagickFalse,channel_features);
1330           break;
1331         }
1332         case LinearGRAYColorspace:
1333         case GRAYColorspace:
1334         {
1335           (void) PrintChannelFeatures(file,GrayPixelChannel,"gray",MagickFalse,
1336             channel_features);
1337           break;
1338         }
1339       }
1340       (void) FormatLocaleFile(file,"    \n");
1341       channel_features=(ChannelFeatures *) RelinquishMagickMemory(
1342         channel_features);
1343     }
1344     if (image->colorspace == CMYKColorspace)
1345       (void) FormatLocaleFile(file,"    totalInkDensity: %.*g%%\n",
1346         GetMagickPrecision(),100.0*GetImageTotalInkDensity(image,exception)/
1347         (double) QuantumRange);
1348     x=0;
1349     if (image->alpha_trait != UndefinedPixelTrait)
1350       {
1351         const Quantum
1352           *p;
1353 
1354         p=(const Quantum *) NULL;
1355         for (y=0; y < (ssize_t) image->rows; y++)
1356         {
1357           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1358           if (p == (const Quantum *) NULL)
1359             break;
1360           for (x=0; x < (ssize_t) image->columns; x++)
1361           {
1362             if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)
1363               break;
1364             p+=GetPixelChannels(image);
1365           }
1366           if (x < (ssize_t) image->columns)
1367             break;
1368         }
1369         if ((x < (ssize_t) image->columns) || (y < (ssize_t) image->rows))
1370           {
1371             PixelInfo
1372               pixel;
1373 
1374             GetPixelInfo(image,&pixel);
1375             GetPixelInfoPixel(image,p,&pixel);
1376             GetColorTuple(&pixel,MagickTrue,color);
1377             (void) FormatLocaleFile(file,"    alpha: '%s'\n",color);
1378           }
1379       }
1380   if (image->storage_class == PseudoClass)
1381     {
1382       PixelInfo
1383         *magick_restrict p;
1384 
1385       (void) FormatLocaleFile(file,"    colormapEntries: %.20g\n",
1386         (double) image->colors);
1387       (void) FormatLocaleFile(file,"    colormap: \n      ");
1388       p=image->colormap;
1389       for (i=0; i < (ssize_t) image->colors; i++)
1390       {
1391         GetColorTuple(p,MagickTrue,color);
1392         (void) FormatLocaleFile(file,"- '%s'\n      ",color);
1393         p++;
1394       }
1395       (void) FormatLocaleFile(file,"\n    \n");
1396     }
1397   if (image->error.mean_error_per_pixel != 0.0)
1398     (void) FormatLocaleFile(file,"    meanErrorPerPixel: %g\n",
1399       image->error.mean_error_per_pixel);
1400   if (image->error.normalized_mean_error != 0.0)
1401     (void) FormatLocaleFile(file,"    normalizedMeanError: %g\n",
1402       image->error.normalized_mean_error);
1403   if (image->error.normalized_maximum_error != 0.0)
1404     (void) FormatLocaleFile(file,"    normalizedMaximumError: %g\n",
1405       image->error.normalized_maximum_error);
1406   YAMLFormatLocaleFile(file,"    renderingIntent: %s\n",
1407     CommandOptionToMnemonic(MagickIntentOptions,(ssize_t)
1408     image->rendering_intent));
1409   if (image->gamma != 0.0)
1410     (void) FormatLocaleFile(file,"    gamma: %g\n",image->gamma);
1411   if ((image->chromaticity.red_primary.x != 0.0) ||
1412       (image->chromaticity.green_primary.x != 0.0) ||
1413       (image->chromaticity.blue_primary.x != 0.0) ||
1414       (image->chromaticity.white_point.x != 0.0))
1415     {
1416       /*
1417         Display image chromaticity.
1418       */
1419       (void) FormatLocaleFile(file,"    chromaticity: \n");
1420       (void) FormatLocaleFile(file,"      redPrimary: \n"
1421         "        x: %g\n        y: %g\n      \n",
1422         image->chromaticity.red_primary.x,image->chromaticity.red_primary.y);
1423       (void) FormatLocaleFile(file,"      greenPrimary: \n"
1424         "        x: %g\n        y: %g\n      \n",
1425         image->chromaticity.green_primary.x,
1426         image->chromaticity.green_primary.y);
1427       (void) FormatLocaleFile(file,"      bluePrimary: \n"
1428         "        x: %g\n        y: %g\n      \n",
1429         image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y);
1430       (void) FormatLocaleFile(file,"      whitePrimary: \n"
1431         "        x: %g\n        y: %g\n      \n",
1432         image->chromaticity.white_point.x,image->chromaticity.white_point.y);
1433       (void) FormatLocaleFile(file,"    \n");
1434     }
1435   if ((image->extract_info.width*image->extract_info.height) != 0)
1436     (void) FormatLocaleFile(file,"    tileGeometry: \n"
1437       "      width: %.20g\n      height: %.20g\n"
1438       "      x: %.20g\n      y: %.20g\n    \n",
1439       (double) image->extract_info.width,(double) image->extract_info.height,
1440       (double) image->extract_info.x,(double) image->extract_info.y);
1441   GetColorTuple(&image->matte_color,MagickTrue,color);
1442   (void) FormatLocaleFile(file,"    matteColor: '%s'\n",color);
1443   GetColorTuple(&image->background_color,MagickTrue,color);
1444   (void) FormatLocaleFile(file,"    backgroundColor: '%s'\n",color);
1445   GetColorTuple(&image->border_color,MagickTrue,color);
1446   (void) FormatLocaleFile(file,"    borderColor: '%s'\n",color);
1447   GetColorTuple(&image->transparent_color,MagickTrue,color);
1448   (void) FormatLocaleFile(file,"    transparentColor: '%s'\n",color);
1449   YAMLFormatLocaleFile(file,"    interlace: %s\n",CommandOptionToMnemonic(
1450     MagickInterlaceOptions,(ssize_t) image->interlace));
1451   YAMLFormatLocaleFile(file,"    intensity: %s\n",CommandOptionToMnemonic(
1452     MagickPixelIntensityOptions,(ssize_t) image->intensity));
1453   YAMLFormatLocaleFile(file,"    compose: %s\n",
1454     CommandOptionToMnemonic(MagickComposeOptions,(ssize_t) image->compose));
1455   if ((image->page.width != 0) || (image->page.height != 0) ||
1456       (image->page.x != 0) || (image->page.y != 0))
1457     (void) FormatLocaleFile(file,"    pageGeometry: \n"
1458       "      width: %.20g\n      height: %.20g\n"
1459       "      x: %.20g\n      y: %.20g\n    \n",
1460       (double) image->page.width,(double) image->page.height,
1461       (double) image->page.x,(double) image->page.y);
1462   if ((image->page.x != 0) || (image->page.y != 0))
1463     (void) FormatLocaleFile(file,"    originGeometry: %+.20g%+.20g\n",
1464       (double) image->page.x,(double) image->page.y);
1465   YAMLFormatLocaleFile(file,"    dispose: %s\n",
1466     CommandOptionToMnemonic(MagickDisposeOptions,(ssize_t) image->dispose));
1467   if (image->delay != 0)
1468     (void) FormatLocaleFile(file,"    delay: %.20gx%.20g\n",
1469       (double) image->delay,(double) image->ticks_per_second);
1470   if (image->iterations != 1)
1471     (void) FormatLocaleFile(file,"    iterations: %.20g\n",(double)
1472       image->iterations);
1473   if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
1474     (void) FormatLocaleFile(file,"    scene: %.20g\n    scenes: "
1475       "%.20g\n",(double) image->scene,(double) GetImageListLength(image));
1476   else
1477     if (image->scene != 0)
1478       (void) FormatLocaleFile(file,"    scene: %.20g\n",(double)
1479         image->scene);
1480   YAMLFormatLocaleFile(file,"    compression: %s\n",
1481     CommandOptionToMnemonic(MagickCompressOptions,(ssize_t)
1482     image->compression));
1483   if (image->quality != UndefinedCompressionQuality)
1484     (void) FormatLocaleFile(file,"    quality: %.20g\n",(double)
1485       image->quality);
1486   YAMLFormatLocaleFile(file,"    orientation: %s\n",
1487     CommandOptionToMnemonic(MagickOrientationOptions,(ssize_t)
1488     image->orientation));
1489   if (image->montage != (char *) NULL)
1490     YAMLFormatLocaleFile(file,"    montage: %s\n",image->montage);
1491   if (image->directory != (char *) NULL)
1492     {
1493       Image
1494         *tile;
1495 
1496       ImageInfo
1497         *image_info;
1498 
1499       char
1500         *p,
1501         *q;
1502 
1503       WarningHandler
1504         handler;
1505 
1506       /*
1507         Display visual image directory.
1508       */
1509       image_info=AcquireImageInfo();
1510       (void) CloneString(&image_info->size,"64x64");
1511       (void) FormatLocaleFile(file,"    montageDirectory: ");
1512       p=image->directory;
1513       while (*p != '\0')
1514       {
1515         q=p;
1516         while ((*q != '\xff') && (*q != '\0'))
1517           q++;
1518         (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1));
1519         p=q+1;
1520         YAMLFormatLocaleFile(file,"\n       - name: %s",
1521           image_info->filename);
1522         handler=SetWarningHandler((WarningHandler) NULL);
1523         tile=ReadImage(image_info,exception);
1524         (void) SetWarningHandler(handler);
1525         if (tile == (Image *) NULL)
1526           {
1527             (void) FormatLocaleFile(file,"    ");
1528             continue;
1529           }
1530         (void) FormatLocaleFile(file,"\n       - info: %.20gx%.20g %s",
1531           (double) tile->magick_columns,(double) tile->magick_rows,
1532           tile->magick);
1533         (void) SignatureImage(tile,exception);
1534         ResetImagePropertyIterator(tile);
1535         property=GetNextImageProperty(tile);
1536         while (property != (const char *) NULL)
1537         {
1538           YAMLFormatLocaleFile(file,"\n       %s: ",property);
1539           value=GetImageProperty(tile,property,exception);
1540           YAMLFormatLocaleFile(file,"%s",value);
1541           property=GetNextImageProperty(tile);
1542         }
1543         tile=DestroyImageList(tile);
1544         (void) FormatLocaleFile(file,"\n    ");
1545       }
1546       (void) FormatLocaleFile(file,"\n");
1547       image_info=DestroyImageInfo(image_info);
1548     }
1549   ResetImagePropertyIterator(image);
1550   property=GetNextImageProperty(image);
1551   if (property != (const char *) NULL)
1552     {
1553       size_t
1554         n;
1555 
1556       /*
1557         Display image properties.
1558       */
1559       n=0;
1560       (void) FormatLocaleFile(file,"    properties: \n");
1561       while (property != (const char *) NULL)
1562       {
1563         if (n++ != 0)
1564           (void) FormatLocaleFile(file,"\n");
1565         YAMLFormatLocaleFile(file,"      %s: ",property);
1566         value=GetImageProperty(image,property,exception);
1567         YAMLFormatLocaleFile(file,"%s",value);
1568         property=GetNextImageProperty(image);
1569       }
1570       (void) FormatLocaleFile(file,"\n    \n");
1571     }
1572   (void) FormatLocaleString(key,MagickPathExtent,"8BIM:1999,2998:#1");
1573   value=GetImageProperty(image,key,exception);
1574   if (value != (const char *) NULL)
1575     {
1576       /*
1577         Display clipping path.
1578       */
1579       YAMLFormatLocaleFile(file,"    clipping path: %s\n",value);
1580     }
1581   ResetImageProfileIterator(image);
1582   name=GetNextImageProfile(image);
1583   if (name != (char *) NULL)
1584     {
1585       const StringInfo
1586         *profile;
1587 
1588       size_t
1589         n;
1590 
1591       /*
1592         Identify image profiles.
1593       */
1594       n=0;
1595       (void) FormatLocaleFile(file,"    profiles: \n");
1596       while (name != (char *) NULL)
1597       {
1598         profile=GetImageProfile(image,name);
1599         if (profile == (StringInfo *) NULL)
1600           continue;
1601         if (n++ != 0)
1602           (void) FormatLocaleFile(file,"\n");
1603         YAMLFormatLocaleFile(file,"      %s: \n",name);
1604         if (LocaleCompare(name,"iptc") == 0)
1605           EncodeIptcProfile(file,profile);
1606         (void) FormatLocaleFile(file,"        length: %.20g",(double)
1607           GetStringInfoLength(profile));
1608         (void) FormatLocaleFile(file,"\n      ");
1609         name=GetNextImageProfile(image);
1610       }
1611       (void) FormatLocaleFile(file,"\n    \n");
1612     }
1613   ResetImageArtifactIterator(image);
1614   artifact=GetNextImageArtifact(image);
1615   if (artifact != (const char *) NULL)
1616     {
1617       ssize_t
1618         n;
1619 
1620       /*
1621         Display image artifacts.
1622       */
1623       n=0;
1624       (void) FormatLocaleFile(file,"    artifacts: \n");
1625       while (artifact != (const char *) NULL)
1626       {
1627         if (n++ != 0)
1628           (void) FormatLocaleFile(file,"\n");
1629         YAMLFormatLocaleFile(file,"      %s: ",artifact);
1630         value=GetImageArtifact(image,artifact);
1631         YAMLFormatLocaleFile(file,"%s",value);
1632         artifact=GetNextImageArtifact(image);
1633       }
1634       (void) FormatLocaleFile(file,"\n    \n");
1635     }
1636   ResetImageRegistryIterator();
1637   registry=GetNextImageRegistry();
1638   if (registry != (const char *) NULL)
1639     {
1640       ssize_t
1641         n;
1642 
1643       /*
1644         Display image registry.
1645       */
1646       (void) FormatLocaleFile(file,"    registry: \n");
1647       n=0;
1648       while (registry != (const char *) NULL)
1649       {
1650         if (n++ != 0)
1651           (void) FormatLocaleFile(file,"\n");
1652         YAMLFormatLocaleFile(file,"      %s: ",registry);
1653         value=(const char *) GetImageRegistry(StringRegistryType,registry,
1654           exception);
1655         YAMLFormatLocaleFile(file,"%s",value);
1656         registry=GetNextImageRegistry();
1657       }
1658       (void) FormatLocaleFile(file,"    \n");
1659     }
1660   (void) FormatLocaleFile(file,"    tainted: %s\n",
1661     image->taint != MagickFalse ? "true" : "false");
1662   (void) FormatMagickSize(image->extent,MagickFalse,"B",MagickPathExtent,
1663     format);
1664   YAMLFormatLocaleFile(file,"    filesize: %s\n",format);
1665   (void) FormatMagickSize((MagickSizeType) image->columns*image->rows,
1666     MagickFalse,"B",MagickPathExtent,format);
1667   if (strlen(format) > 1)
1668     format[strlen(format)-1]='\0';
1669   YAMLFormatLocaleFile(file,"    numberPixels: %s\n",format);
1670   (void) FormatMagickSize((MagickSizeType) ((double) image->columns*image->rows/
1671     elapsed_time+0.5),MagickFalse,"B",MagickPathExtent,format);
1672   YAMLFormatLocaleFile(file,"    pixelsPerSecond: %s\n",format);
1673   (void) FormatLocaleFile(file,"    userTime: %0.3fu\n",user_time);
1674   (void) FormatLocaleFile(file,"    elapsedTime: %lu:%02lu.%03lu\n",
1675     (unsigned long) (elapsed_time/60.0),(unsigned long) ceil(fmod(
1676     elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-floor(
1677     elapsed_time))));
1678   YAMLFormatLocaleFile(file,"    version: %s\n",GetMagickVersion(
1679     (size_t *) NULL));
1680   (void) FormatLocaleFile(file,"...\n");
1681   (void) fflush(file);
1682   return(ferror(file) != 0 ? MagickFalse : MagickTrue);
1683 }
1684 
WriteYAMLImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1685 static MagickBooleanType WriteYAMLImage(const ImageInfo *image_info,
1686   Image *image,ExceptionInfo *exception)
1687 {
1688   FILE
1689     *file;
1690 
1691   MagickBooleanType
1692     status;
1693 
1694   MagickOffsetType
1695     scene;
1696 
1697   size_t
1698     number_scenes;
1699 
1700   /*
1701     Open output image file.
1702   */
1703   assert(image_info != (const ImageInfo *) NULL);
1704   assert(image_info->signature == MagickCoreSignature);
1705   assert(image != (Image *) NULL);
1706   assert(image->signature == MagickCoreSignature);
1707   if (image->debug != MagickFalse)
1708     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1709   status=OpenBlob(image_info,image,WriteBlobMode,exception);
1710   if (status == MagickFalse)
1711     return(status);
1712   file=GetBlobFileHandle(image);
1713   if (file == (FILE *) NULL)
1714     file=stdout;
1715   scene=0;
1716   number_scenes=GetImageListLength(image);
1717   do
1718   {
1719     image->magick_columns=image->columns;
1720     image->magick_rows=image->rows;
1721     (void) EncodeImageAttributes(image,file,exception);
1722     if (GetNextImageInList(image) == (Image *) NULL)
1723       break;
1724     image=SyncNextImageInList(image);
1725     status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes);
1726     if (status == MagickFalse)
1727       break;
1728   } while (image_info->adjoin != MagickFalse);
1729   (void) CloseBlob(image);
1730   return(MagickTrue);
1731 }
1732