1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                                                                             %
7 %           V   V   AAA   L      IIIII  DDDD    AAA   TTTTT  EEEEE            %
8 %           V   V  A   A  L        I    D   D  A   A    T    E                %
9 %           V   V  AAAAA  L        I    D   D  AAAAA    T    EEE              %
10 %            V V   A   A  L        I    D   D  A   A    T    E                %
11 %             V    A   A  LLLLL  IIIII  DDDD   A   A    T    EEEEE            %
12 %                                                                             %
13 %                                                                             %
14 %                        ImageMagick Validation Suite                         %
15 %                                                                             %
16 %                             Software Design                                 %
17 %                                  Cristy                                     %
18 %                               March 2001                                    %
19 %                                                                             %
20 %                                                                             %
21 %  Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization      %
22 %  dedicated to making software imaging solutions freely available.           %
23 %                                                                             %
24 %  You may not use this file except in compliance with the License.  You may  %
25 %  obtain a copy of the License at                                            %
26 %                                                                             %
27 %    https://imagemagick.org/script/license.php                               %
28 %                                                                             %
29 %  Unless required by applicable law or agreed to in writing, software        %
30 %  distributed under the License is distributed on an "AS IS" BASIS,          %
31 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32 %  see the License for the specific language governing permissions and        %
33 %  limitations under the License.                                             %
34 %                                                                             %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %
37 %
38 */
39 
40 /*
41   Include declarations.
42 */
43 #include "MagickWand/studio.h"
44 #include "MagickWand/MagickWand.h"
45 #include "MagickCore/colorspace-private.h"
46 #include "MagickCore/gem.h"
47 #include "MagickCore/resource_.h"
48 #include "MagickCore/string-private.h"
49 #include "validate.h"
50 
51 /*
52   Define declarations.
53 */
54 #if defined(__APPLE__)
55   #include "TargetConditionals.h"
56   #if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
57     #define system(s) ((s)==NULL ? 0 : -1)
58   #endif // end iOS
59 #elif defined(__ANDROID__)
60   #define system(s) ((s)==NULL ? 0 : -1)
61 #endif
62 #define CIEEpsilon  (216.0/24389.0)
63 #define CIEK  (24389.0/27.0)
64 #define D65X  0.95047
65 #define D65Y  1.0
66 #define D65Z  1.08883
67 #define ReferenceEpsilon  (QuantumRange*1.0e-2)
68 
69 /*
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71 %                                                                             %
72 %                                                                             %
73 %                                                                             %
74 %   V a l i d a t e C o l o r s p a c e s                                     %
75 %                                                                             %
76 %                                                                             %
77 %                                                                             %
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 %
80 %  ValidateColorspaces() validates the ImageMagick colorspaces and returns the
81 %  number of validation tests that passed and failed.
82 %
83 %  The format of the ValidateColorspaces method is:
84 %
85 %      size_t ValidateColorspaces(ImageInfo *image_info,size_t *fails,
86 %        ExceptionInfo *exception)
87 %
88 %  A description of each parameter follows:
89 %
90 %    o image_info: the image info.
91 %
92 %    o fail: return the number of validation tests that pass.
93 %
94 %    o exception: return any errors or warnings in this structure.
95 %
96 */
97 
ConvertHSIToRGB(const double hue,const double saturation,const double intensity,double * red,double * green,double * blue)98 static void ConvertHSIToRGB(const double hue,const double saturation,
99   const double intensity,double *red,double *green,double *blue)
100 {
101   double
102     h;
103 
104   h=360.0*hue;
105   h-=360.0*floor(h/360.0);
106   if (h < 120.0)
107     {
108       *blue=intensity*(1.0-saturation);
109       *red=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
110         (MagickPI/180.0)));
111       *green=3.0*intensity-*red-*blue;
112     }
113   else
114     if (h < 240.0)
115       {
116         h-=120.0;
117         *red=intensity*(1.0-saturation);
118         *green=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
119           (MagickPI/180.0)));
120         *blue=3.0*intensity-*red-*green;
121       }
122     else
123       {
124         h-=240.0;
125         *green=intensity*(1.0-saturation);
126         *blue=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
127           (MagickPI/180.0)));
128         *red=3.0*intensity-*green-*blue;
129       }
130   *red*=QuantumRange;
131   *green*=QuantumRange;
132   *blue*=QuantumRange;
133 }
134 
ConvertRGBToHSI(const double red,const double green,const double blue,double * hue,double * saturation,double * intensity)135 static void ConvertRGBToHSI(const double red,const double green,
136   const double blue,double *hue,double *saturation,double *intensity)
137 {
138   double
139     alpha,
140     beta;
141 
142   *intensity=(QuantumScale*red+QuantumScale*green+QuantumScale*blue)/3.0;
143   if (*intensity <= 0.0)
144     {
145       *hue=0.0;
146       *saturation=0.0;
147       return;
148     }
149   *saturation=1.0-MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
150     QuantumScale*blue))/(*intensity);
151   alpha=0.5*(2.0*QuantumScale*red-QuantumScale*green-QuantumScale*blue);
152   beta=0.8660254037844385*(QuantumScale*green-QuantumScale*blue);
153   *hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
154   if (*hue < 0.0)
155     *hue+=1.0;
156 }
157 
ConvertHSVToRGB(const double hue,const double saturation,const double value,double * red,double * green,double * blue)158 static void ConvertHSVToRGB(const double hue,const double saturation,
159   const double value,double *red,double *green,double *blue)
160 {
161   double
162     c,
163     h,
164     min,
165     x;
166 
167   h=hue*360.0;
168   c=value*saturation;
169   min=value-c;
170   h-=360.0*floor(h/360.0);
171   h/=60.0;
172   x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
173   switch ((int) floor(h))
174   {
175     case 0:
176     {
177       *red=QuantumRange*(min+c);
178       *green=QuantumRange*(min+x);
179       *blue=QuantumRange*min;
180       break;
181     }
182     case 1:
183     {
184       *red=QuantumRange*(min+x);
185       *green=QuantumRange*(min+c);
186       *blue=QuantumRange*min;
187       break;
188     }
189     case 2:
190     {
191       *red=QuantumRange*min;
192       *green=QuantumRange*(min+c);
193       *blue=QuantumRange*(min+x);
194       break;
195     }
196     case 3:
197     {
198       *red=QuantumRange*min;
199       *green=QuantumRange*(min+x);
200       *blue=QuantumRange*(min+c);
201       break;
202     }
203     case 4:
204     {
205       *red=QuantumRange*(min+x);
206       *green=QuantumRange*min;
207       *blue=QuantumRange*(min+c);
208       break;
209     }
210     case 5:
211     {
212       *red=QuantumRange*(min+c);
213       *green=QuantumRange*min;
214       *blue=QuantumRange*(min+x);
215       break;
216     }
217     default:
218     {
219       *red=0.0;
220       *green=0.0;
221       *blue=0.0;
222     }
223   }
224 }
225 
ConvertRGBToXYZ(const double red,const double green,const double blue,double * X,double * Y,double * Z)226 static inline void ConvertRGBToXYZ(const double red,const double green,
227   const double blue,double *X,double *Y,double *Z)
228 {
229   double
230     b,
231     g,
232     r;
233 
234   r=QuantumScale*DecodePixelGamma(red);
235   g=QuantumScale*DecodePixelGamma(green);
236   b=QuantumScale*DecodePixelGamma(blue);
237   *X=0.41239558896741421610*r+0.35758343076371481710*g+0.18049264738170157350*b;
238   *Y=0.21258623078559555160*r+0.71517030370341084990*g+0.07220049864333622685*b;
239   *Z=0.01929721549174694484*r+0.11918386458084853180*g+0.95049712513157976600*b;
240 }
241 
ConvertXYZToLab(const double X,const double Y,const double Z,double * L,double * a,double * b)242 static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
243   double *L,double *a,double *b)
244 {
245   double
246     x,
247     y,
248     z;
249 
250   if ((X/D65X) > CIEEpsilon)
251     x=pow(X/D65X,1.0/3.0);
252   else
253     x=(CIEK*X/D65X+16.0)/116.0;
254   if ((Y/D65Y) > CIEEpsilon)
255     y=pow(Y/D65Y,1.0/3.0);
256   else
257     y=(CIEK*Y/D65Y+16.0)/116.0;
258   if ((Z/D65Z) > CIEEpsilon)
259     z=pow(Z/D65Z,1.0/3.0);
260   else
261     z=(CIEK*Z/D65Z+16.0)/116.0;
262   *L=((116.0*y)-16.0)/100.0;
263   *a=(500.0*(x-y))/255.0+0.5;
264   *b=(200.0*(y-z))/255.0+0.5;
265 }
266 
ConvertRGBToLab(const double red,const double green,const double blue,double * L,double * a,double * b)267 static void ConvertRGBToLab(const double red,const double green,
268   const double blue,double *L,double *a,double *b)
269 {
270   double
271     X,
272     Y,
273     Z;
274 
275   ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
276   ConvertXYZToLab(X,Y,Z,L,a,b);
277 }
278 
ConvertLabToXYZ(const double L,const double a,const double b,double * X,double * Y,double * Z)279 static inline void ConvertLabToXYZ(const double L,const double a,const double b,
280   double *X,double *Y,double *Z)
281 {
282   double
283     x,
284     y,
285     z;
286 
287   y=(L+16.0)/116.0;
288   x=y+a/500.0;
289   z=y-b/200.0;
290   if ((x*x*x) > CIEEpsilon)
291     x=(x*x*x);
292   else
293     x=(116.0*x-16.0)/CIEK;
294   if ((y*y*y) > CIEEpsilon)
295     y=(y*y*y);
296   else
297     y=L/CIEK;
298   if ((z*z*z) > CIEEpsilon)
299     z=(z*z*z);
300   else
301     z=(116.0*z-16.0)/CIEK;
302   *X=D65X*x;
303   *Y=D65Y*y;
304   *Z=D65Z*z;
305 }
306 
ConvertXYZToRGB(const double x,const double y,const double z,double * red,double * green,double * blue)307 static inline void ConvertXYZToRGB(const double x,const double y,const double z,
308   double *red,double *green,double *blue)
309 {
310   double
311     b,
312     g,
313     r;
314 
315   r=3.2406*x-1.5372*y-0.4986*z;
316   g=(-0.9689*x+1.8758*y+0.0415*z);
317   b=0.0557*x-0.2040*y+1.0570*z;
318   *red=EncodePixelGamma(QuantumRange*r);
319   *green=EncodePixelGamma(QuantumRange*g);
320   *blue=EncodePixelGamma(QuantumRange*b);
321 }
322 
ConvertLabToRGB(const double L,const double a,const double b,double * red,double * green,double * blue)323 static inline void ConvertLabToRGB(const double L,const double a,
324   const double b,double *red,double *green,double *blue)
325 {
326   double
327     X,
328     Y,
329     Z;
330 
331   ConvertLabToXYZ(L*100.0,255.0*(a-0.5),255.0*(b-0.5),&X,&Y,&Z);
332   ConvertXYZToRGB(X,Y,Z,red,green,blue);
333 }
334 
ConvertRGBToYPbPr(const double red,const double green,const double blue,double * Y,double * Pb,double * Pr)335 static void ConvertRGBToYPbPr(const double red,const double green,
336   const double blue,double *Y,double *Pb,double *Pr)
337 {
338   *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
339   *Pb=QuantumScale*((-0.1687367)*red-0.331264*green+0.5*blue)+0.5;
340   *Pr=QuantumScale*(0.5*red-0.418688*green-0.081312*blue)+0.5;
341 }
342 
ConvertRGBToYCbCr(const double red,const double green,const double blue,double * Y,double * Cb,double * Cr)343 static void ConvertRGBToYCbCr(const double red,const double green,
344   const double blue,double *Y,double *Cb,double *Cr)
345 {
346   ConvertRGBToYPbPr(red,green,blue,Y,Cb,Cr);
347 }
348 
ConvertYPbPrToRGB(const double Y,const double Pb,const double Pr,double * red,double * green,double * blue)349 static void ConvertYPbPrToRGB(const double Y,const double Pb,const double Pr,
350   double *red,double *green,double *blue)
351 {
352   *red=QuantumRange*(0.99999999999914679361*Y-1.2188941887145875e-06*(Pb-0.5)+
353     1.4019995886561440468*(Pr-0.5));
354   *green=QuantumRange*(0.99999975910502514331*Y-0.34413567816504303521*(Pb-0.5)-
355     0.71413649331646789076*(Pr-0.5));
356   *blue=QuantumRange*(1.00000124040004623180*Y+1.77200006607230409200*(Pb-0.5)+
357     2.1453384174593273e-06*(Pr-0.5));
358 }
359 
ConvertYCbCrToRGB(const double Y,const double Cb,const double Cr,double * red,double * green,double * blue)360 static void ConvertYCbCrToRGB(const double Y,const double Cb,
361   const double Cr,double *red,double *green,double *blue)
362 {
363   ConvertYPbPrToRGB(Y,Cb,Cr,red,green,blue);
364 }
365 
ConvertLCHabToXYZ(const double luma,const double chroma,const double hue,double * X,double * Y,double * Z)366 static inline void ConvertLCHabToXYZ(const double luma,const double chroma,
367   const double hue,double *X,double *Y,double *Z)
368 {
369   ConvertLabToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
370     sin(hue*MagickPI/180.0),X,Y,Z);
371 }
372 
ConvertLCHabToRGB(const double luma,const double chroma,const double hue,double * red,double * green,double * blue)373 static void ConvertLCHabToRGB(const double luma,const double chroma,
374   const double hue,double *red,double *green,double *blue)
375 {
376   double
377     X,
378     Y,
379     Z;
380 
381   ConvertLCHabToXYZ(luma*100.0,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
382   ConvertXYZToRGB(X,Y,Z,red,green,blue);
383 }
384 
ConvertRGBToHSV(const double red,const double green,const double blue,double * hue,double * saturation,double * value)385 static void ConvertRGBToHSV(const double red,const double green,
386   const double blue,double *hue,double *saturation,double *value)
387 {
388   double
389     c,
390     max,
391     min;
392 
393   max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
394     QuantumScale*blue));
395   min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
396     QuantumScale*blue));
397   c=max-min;
398   *value=max;
399   if (c <= 0.0)
400     {
401       *hue=0.0;
402       *saturation=0.0;
403       return;
404     }
405   if (max == (QuantumScale*red))
406     {
407       *hue=(QuantumScale*green-QuantumScale*blue)/c;
408       if ((QuantumScale*green) < (QuantumScale*blue))
409         *hue+=6.0;
410     }
411   else
412     if (max == (QuantumScale*green))
413       *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
414     else
415       *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
416   *hue*=60.0/360.0;
417   *saturation=c/max;
418 }
419 
ConvertXYZToLCHab(const double X,const double Y,const double Z,double * luma,double * chroma,double * hue)420 static inline void ConvertXYZToLCHab(const double X,const double Y,
421   const double Z,double *luma,double *chroma,double *hue)
422 {
423   double
424     a,
425     b;
426 
427   ConvertXYZToLab(X,Y,Z,luma,&a,&b);
428   *chroma=hypot(255.0*(a-0.5),255.0*(b-0.5))/255.0+0.5;
429   *hue=180.0*atan2(255.0*(b-0.5),255.0*(a-0.5))/MagickPI/360.0;
430   if (*hue < 0.0)
431     *hue+=1.0;
432 }
433 
ConvertRGBToLCHab(const double red,const double green,const double blue,double * luma,double * chroma,double * hue)434 static void ConvertRGBToLCHab(const double red,const double green,
435   const double blue,double *luma,double *chroma,double *hue)
436 {
437   double
438     X,
439     Y,
440     Z;
441 
442   ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
443   ConvertXYZToLCHab(X,Y,Z,luma,chroma,hue);
444 }
445 
ConvertLMSToXYZ(const double L,const double M,const double S,double * X,double * Y,double * Z)446 static inline void ConvertLMSToXYZ(const double L,const double M,const double S,
447   double *X,double *Y,double *Z)
448 {
449   *X=1.096123820835514*L-0.278869000218287*M+0.182745179382773*S;
450   *Y=0.454369041975359*L+0.473533154307412*M+0.072097803717229*S;
451   *Z=(-0.009627608738429)*L-0.005698031216113*M+1.015325639954543*S;
452 }
453 
ConvertLMSToRGB(const double L,const double M,const double S,double * red,double * green,double * blue)454 static inline void ConvertLMSToRGB(const double L,const double M,
455   const double S,double *red,double *green,double *blue)
456 {
457   double
458     X,
459     Y,
460     Z;
461 
462   ConvertLMSToXYZ(L,M,S,&X,&Y,&Z);
463   ConvertXYZToRGB(X,Y,Z,red,green,blue);
464 }
465 
ConvertXYZToLMS(const double x,const double y,const double z,double * L,double * M,double * S)466 static inline void ConvertXYZToLMS(const double x,const double y,
467   const double z,double *L,double *M,double *S)
468 {
469   *L=0.7328*x+0.4296*y-0.1624*z;
470   *M=(-0.7036*x+1.6975*y+0.0061*z);
471   *S=0.0030*x+0.0136*y+0.9834*z;
472 }
473 
ConvertRGBToLMS(const double red,const double green,const double blue,double * L,double * M,double * S)474 static void ConvertRGBToLMS(const double red,const double green,
475   const double blue,double *L,double *M,double *S)
476 {
477   double
478     X,
479     Y,
480     Z;
481 
482   ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
483   ConvertXYZToLMS(X,Y,Z,L,M,S);
484 }
485 
ConvertXYZToLuv(const double X,const double Y,const double Z,double * L,double * u,double * v)486 static inline void ConvertXYZToLuv(const double X,const double Y,const double Z,
487   double *L,double *u,double *v)
488 {
489   double
490     alpha;
491 
492   if ((Y/D65Y) > CIEEpsilon)
493     *L=(double) (116.0*pow(Y/D65Y,1.0/3.0)-16.0);
494   else
495     *L=CIEK*(Y/D65Y);
496   alpha=PerceptibleReciprocal(X+15.0*Y+3.0*Z);
497   *u=13.0*(*L)*((4.0*alpha*X)-(4.0*D65X/(D65X+15.0*D65Y+3.0*D65Z)));
498   *v=13.0*(*L)*((9.0*alpha*Y)-(9.0*D65Y/(D65X+15.0*D65Y+3.0*D65Z)));
499   *L/=100.0;
500   *u=(*u+134.0)/354.0;
501   *v=(*v+140.0)/262.0;
502 }
503 
ConvertRGBToLuv(const double red,const double green,const double blue,double * L,double * u,double * v)504 static void ConvertRGBToLuv(const double red,const double green,
505   const double blue,double *L,double *u,double *v)
506 {
507   double
508     X,
509     Y,
510     Z;
511 
512   ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
513   ConvertXYZToLuv(X,Y,Z,L,u,v);
514 }
515 
ConvertLuvToXYZ(const double L,const double u,const double v,double * X,double * Y,double * Z)516 static inline void ConvertLuvToXYZ(const double L,const double u,const double v,
517   double *X,double *Y,double *Z)
518 {
519   if (L > (CIEK*CIEEpsilon))
520     *Y=(double) pow((L+16.0)/116.0,3.0);
521   else
522     *Y=L/CIEK;
523   *X=((*Y*((39.0*L/(v+13.0*L*(9.0*D65Y/(D65X+15.0*D65Y+3.0*D65Z))))-5.0))+
524     5.0*(*Y))/((((52.0f*L/(u+13.0*L*(4.0*D65X/(D65X+15.0*D65Y+3.0*D65Z))))-1.0)/
525     3.0)-(-1.0/3.0));
526   *Z=(*X*(((52.0f*L/(u+13.0*L*(4.0*D65X/(D65X+15.0*D65Y+3.0*D65Z))))-1.0)/3.0))-
527     5.0*(*Y);
528 }
529 
ConvertLuvToRGB(const double L,const double u,const double v,double * red,double * green,double * blue)530 static inline void ConvertLuvToRGB(const double L,const double u,
531   const double v,double *red,double *green,double *blue)
532 {
533   double
534     X,
535     Y,
536     Z;
537 
538   ConvertLuvToXYZ(100.0*L,354.0*u-134.0,262.0*v-140.0,&X,&Y,&Z);
539   ConvertXYZToRGB(X,Y,Z,red,green,blue);
540 }
541 
ConvertRGBToYDbDr(const double red,const double green,const double blue,double * Y,double * Db,double * Dr)542 static void ConvertRGBToYDbDr(const double red,const double green,
543   const double blue,double *Y,double *Db,double *Dr)
544 {
545   *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
546   *Db=QuantumScale*(-0.450*red-0.883*green+1.333*blue)+0.5;
547   *Dr=QuantumScale*(-1.333*red+1.116*green+0.217*blue)+0.5;
548 }
549 
ConvertYDbDrToRGB(const double Y,const double Db,const double Dr,double * red,double * green,double * blue)550 static void ConvertYDbDrToRGB(const double Y,const double Db,const double Dr,
551   double *red,double *green,double *blue)
552 {
553   *red=QuantumRange*(Y+9.2303716147657e-05*(Db-0.5)-0.52591263066186533*
554     (Dr-0.5));
555   *green=QuantumRange*(Y-0.12913289889050927*(Db-0.5)+0.26789932820759876*
556     (Dr-0.5));
557   *blue=QuantumRange*(Y+0.66467905997895482*(Db-0.5)-7.9202543533108e-05*
558     (Dr-0.5));
559 }
560 
ConvertRGBToYIQ(const double red,const double green,const double blue,double * Y,double * I,double * Q)561 static void ConvertRGBToYIQ(const double red,const double green,
562   const double blue,double *Y,double *I,double *Q)
563 {
564   *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
565   *I=QuantumScale*(0.595716*red-0.274453*green-0.321263*blue)+0.5;
566   *Q=QuantumScale*(0.211456*red-0.522591*green+0.311135*blue)+0.5;
567 }
568 
ConvertYIQToRGB(const double Y,const double I,const double Q,double * red,double * green,double * blue)569 static void ConvertYIQToRGB(const double Y,const double I,const double Q,
570   double *red,double *green,double *blue)
571 {
572   *red=QuantumRange*(Y+0.9562957197589482261*(I-0.5)+0.6210244164652610754*
573     (Q-0.5));
574   *green=QuantumRange*(Y-0.2721220993185104464*(I-0.5)-0.6473805968256950427*
575     (Q-0.5));
576   *blue=QuantumRange*(Y-1.1069890167364901945*(I-0.5)+1.7046149983646481374*
577     (Q-0.5));
578 }
579 
ConvertRGBToYUV(const double red,const double green,const double blue,double * Y,double * U,double * V)580 static void ConvertRGBToYUV(const double red,const double green,
581   const double blue,double *Y,double *U,double *V)
582 {
583   *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
584   *U=QuantumScale*((-0.147)*red-0.289*green+0.436*blue)+0.5;
585   *V=QuantumScale*(0.615*red-0.515*green-0.100*blue)+0.5;
586 }
587 
ConvertYUVToRGB(const double Y,const double U,const double V,double * red,double * green,double * blue)588 static void ConvertYUVToRGB(const double Y,const double U,const double V,
589   double *red,double *green,double *blue)
590 {
591   *red=QuantumRange*(Y-3.945707070708279e-05*(U-0.5)+1.1398279671717170825*
592     (V-0.5));
593   *green=QuantumRange*(Y-0.3946101641414141437*(U-0.5)-0.5805003156565656797*
594     (V-0.5));
595   *blue=QuantumRange*(Y+2.0319996843434342537*(U-0.5)-4.813762626262513e-04*
596     (V-0.5));
597 }
598 
ValidateHSIToRGB()599 static MagickBooleanType ValidateHSIToRGB()
600 {
601   double
602     r,
603     g,
604     b;
605 
606   (void) FormatLocaleFile(stdout,"  HSIToRGB");
607   ConvertHSIToRGB(111.244375/360.0,0.295985,0.658734,&r,&g,&b);
608   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
609       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
610       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
611     return(MagickFalse);
612   return(MagickTrue);
613 }
614 
ValidateRGBToHSI()615 static MagickBooleanType ValidateRGBToHSI()
616 {
617   double
618     h,
619     i,
620     s;
621 
622   (void) FormatLocaleFile(stdout,"  RGBToHSI");
623   ConvertRGBToHSI(0.545877*QuantumRange,0.966567*QuantumRange,
624     0.463759*QuantumRange,&h,&s,&i);
625   if ((fabs(h-111.244374/360.0) >= ReferenceEpsilon) ||
626       (fabs(s-0.295985) >= ReferenceEpsilon) ||
627       (fabs(i-0.658734) >= ReferenceEpsilon))
628     return(MagickFalse);
629   return(MagickTrue);
630 }
631 
ValidateHSLToRGB()632 static MagickBooleanType ValidateHSLToRGB()
633 {
634   double
635     r,
636     g,
637     b;
638 
639   (void) FormatLocaleFile(stdout,"  HSLToRGB");
640   ConvertHSLToRGB(110.200859/360.0,0.882623,0.715163,&r,&g,&b);
641   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
642       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
643       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
644     return(MagickFalse);
645   return(MagickTrue);
646 }
647 
ValidateRGBToHSL()648 static MagickBooleanType ValidateRGBToHSL()
649 {
650   double
651     h,
652     l,
653     s;
654 
655   (void) FormatLocaleFile(stdout,"  RGBToHSL");
656   ConvertRGBToHSL(0.545877*QuantumRange,0.966567*QuantumRange,
657     0.463759*QuantumRange,&h,&s,&l);
658   if ((fabs(h-110.200859/360.0) >= ReferenceEpsilon) ||
659       (fabs(s-0.882623) >= ReferenceEpsilon) ||
660       (fabs(l-0.715163) >= ReferenceEpsilon))
661     return(MagickFalse);
662   return(MagickTrue);
663 }
664 
ValidateHSVToRGB()665 static MagickBooleanType ValidateHSVToRGB()
666 {
667   double
668     r,
669     g,
670     b;
671 
672   (void) FormatLocaleFile(stdout,"  HSVToRGB");
673   ConvertHSVToRGB(110.200859/360.0,0.520200,0.966567,&r,&g,&b);
674   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
675       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
676       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
677     return(MagickFalse);
678   return(MagickTrue);
679 }
680 
ValidateRGBToHSV()681 static MagickBooleanType ValidateRGBToHSV()
682 {
683   double
684     h,
685     s,
686     v;
687 
688   (void) FormatLocaleFile(stdout,"  RGBToHSV");
689   ConvertRGBToHSV(0.545877*QuantumRange,0.966567*QuantumRange,
690     0.463759*QuantumRange,&h,&s,&v);
691   if ((fabs(h-110.200859/360.0) >= ReferenceEpsilon) ||
692       (fabs(s-0.520200) >= ReferenceEpsilon) ||
693       (fabs(v-0.966567) >= ReferenceEpsilon))
694     return(MagickFalse);
695   return(MagickTrue);
696 }
697 
ValidateRGBToJPEGYCbCr()698 static MagickBooleanType ValidateRGBToJPEGYCbCr()
699 {
700   double
701     Cb,
702     Cr,
703     Y;
704 
705   (void) FormatLocaleFile(stdout,"  RGBToJPEGYCbCr");
706   ConvertRGBToYCbCr(0.545877*QuantumRange,0.966567*QuantumRange,
707     0.463759*QuantumRange,&Y,&Cb,&Cr);
708   if ((fabs(Y-0.783460) >= ReferenceEpsilon) ||
709       (fabs(Cb-0.319581) >= ReferenceEpsilon) ||
710       (fabs(Cr-0.330539) >= ReferenceEpsilon))
711     return(MagickFalse);
712   return(MagickTrue);
713 }
714 
ValidateJPEGYCbCrToRGB()715 static MagickBooleanType ValidateJPEGYCbCrToRGB()
716 {
717   double
718     r,
719     g,
720     b;
721 
722   (void) FormatLocaleFile(stdout,"  JPEGYCbCrToRGB");
723   ConvertYCbCrToRGB(0.783460,0.319581,0.330539,&r,&g,&b);
724   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
725       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
726       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
727     return(MagickFalse);
728   return(MagickTrue);
729 }
730 
ValidateLabToRGB()731 static MagickBooleanType ValidateLabToRGB()
732 {
733   double
734     r,
735     g,
736     b;
737 
738   (void) FormatLocaleFile(stdout,"  LabToRGB");
739   ConvertLabToRGB(88.456154/100.0,-54.671483/255+0.5,51.662818/255.0+0.5,
740     &r,&g,&b);
741   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
742       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
743       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
744     return(MagickFalse);
745   return(MagickTrue);
746 }
747 
ValidateRGBToLab()748 static MagickBooleanType ValidateRGBToLab()
749 {
750   double
751     a,
752     b,
753     L;
754 
755   (void) FormatLocaleFile(stdout,"  RGBToLab");
756   ConvertRGBToLab(0.545877*QuantumRange,0.966567*QuantumRange,
757     0.463759*QuantumRange,&L,&a,&b);
758   if ((fabs(L-(88.456154/100.0)) >= ReferenceEpsilon) ||
759       (fabs(a-(-54.671483/255.0+0.5)) >= ReferenceEpsilon) ||
760       (fabs(b-(51.662818/255.0+0.5)) >= ReferenceEpsilon))
761     return(MagickFalse);
762   return(MagickTrue);
763 }
764 
ValidateLchToRGB()765 static MagickBooleanType ValidateLchToRGB()
766 {
767   double
768     b,
769     g,
770     r;
771 
772   (void) FormatLocaleFile(stdout,"  LchToRGB");
773   ConvertLCHabToRGB(88.456154/100.0,75.219797/255.0+0.5,136.620717/360.0,
774     &r,&g,&b);
775   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
776       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
777       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
778     return(MagickFalse);
779   return(MagickTrue);
780 }
781 
ValidateRGBToLch()782 static MagickBooleanType ValidateRGBToLch()
783 {
784   double
785     c,
786     h,
787     L;
788 
789   (void) FormatLocaleFile(stdout,"  RGBToLch");
790   ConvertRGBToLCHab(0.545877*QuantumRange,0.966567*QuantumRange,
791     0.463759*QuantumRange,&L,&c,&h);
792   if ((fabs(L-88.456154/100.0) >= ReferenceEpsilon) ||
793       (fabs(c-(75.219797/255.0+0.5)) >= ReferenceEpsilon) ||
794       (fabs(h-(136.620717/255.0+0.5)) >= ReferenceEpsilon))
795     return(MagickFalse);
796   return(MagickTrue);
797 }
798 
ValidateRGBToLMS()799 static MagickBooleanType ValidateRGBToLMS()
800 {
801   double
802     L,
803     M,
804     S;
805 
806   (void) FormatLocaleFile(stdout,"  RGBToLMS");
807   ConvertRGBToLMS(0.545877*QuantumRange,0.966567*QuantumRange,
808     0.463759*QuantumRange,&L,&M,&S);
809   if ((fabs(L-0.611749) >= ReferenceEpsilon) ||
810       (fabs(M-0.910088) >= ReferenceEpsilon) ||
811       (fabs(S-0.294880) >= ReferenceEpsilon))
812     return(MagickFalse);
813   return(MagickTrue);
814 }
815 
ValidateLMSToRGB()816 static MagickBooleanType ValidateLMSToRGB()
817 {
818   double
819     r,
820     g,
821     b;
822 
823   (void) FormatLocaleFile(stdout,"  LMSToRGB");
824   ConvertLMSToRGB(0.611749,0.910088,0.294880,&r,&g,&b);
825   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
826       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
827       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
828     return(MagickFalse);
829   return(MagickTrue);
830 }
831 
ValidateRGBToLuv()832 static MagickBooleanType ValidateRGBToLuv()
833 {
834   double
835     l,
836     u,
837     v;
838 
839   (void) FormatLocaleFile(stdout,"  RGBToLuv");
840   ConvertRGBToLuv(0.545877*QuantumRange,0.966567*QuantumRange,
841     0.463759*QuantumRange,&l,&u,&v);
842   if ((fabs(l-88.456154/262.0) >= ReferenceEpsilon) ||
843       (fabs(u-(-51.330414+134.0)/354.0) >= ReferenceEpsilon) ||
844       (fabs(v-(76.405526+140.0)/262.0) >= ReferenceEpsilon))
845     return(MagickFalse);
846   return(MagickTrue);
847 }
848 
ValidateLuvToRGB()849 static MagickBooleanType ValidateLuvToRGB()
850 {
851   double
852     r,
853     g,
854     b;
855 
856   (void) FormatLocaleFile(stdout,"  LuvToRGB");
857   ConvertLuvToRGB(88.456154/100.0,(-51.330414+134.0)/354.0,
858     (76.405526+140.0)/262.0,&r,&g,&b);
859   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
860       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
861       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
862     return(MagickFalse);
863   return(MagickTrue);
864 }
865 
ValidateRGBToXYZ()866 static MagickBooleanType ValidateRGBToXYZ()
867 {
868   double
869     x,
870     y,
871     z;
872 
873   (void) FormatLocaleFile(stdout,"  RGBToXYZ");
874   ConvertRGBToXYZ(0.545877*QuantumRange,0.966567*QuantumRange,
875     0.463759*QuantumRange,&x,&y,&z);
876   if ((fabs(x-0.470646) >= ReferenceEpsilon) ||
877       (fabs(y-0.730178) >= ReferenceEpsilon) ||
878       (fabs(z-0.288324) >= ReferenceEpsilon))
879     return(MagickFalse);
880   return(MagickTrue);
881 }
882 
ValidateXYZToRGB()883 static MagickBooleanType ValidateXYZToRGB()
884 {
885   double
886     r,
887     g,
888     b;
889 
890   (void) FormatLocaleFile(stdout,"  XYZToRGB");
891   ConvertXYZToRGB(0.470646,0.730178,0.288324,&r,&g,&b);
892   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
893       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
894       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
895     return(MagickFalse);
896   return(MagickTrue);
897 }
898 
ValidateYDbDrToRGB()899 static MagickBooleanType ValidateYDbDrToRGB()
900 {
901   double
902     r,
903     g,
904     b;
905 
906   (void) FormatLocaleFile(stdout,"  YDbDrToRGB");
907   ConvertYDbDrToRGB(0.783460,-0.480932+0.5,0.451670+0.5,&r,&g,&b);
908   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
909       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
910       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
911     return(MagickFalse);
912   return(MagickTrue);
913 }
914 
ValidateRGBToYDbDr()915 static MagickBooleanType ValidateRGBToYDbDr()
916 {
917   double
918     Db,
919     Dr,
920     Y;
921 
922   (void) FormatLocaleFile(stdout,"  RGBToYDbDr");
923   ConvertRGBToYDbDr(0.545877*QuantumRange,0.966567*QuantumRange,
924     0.463759*QuantumRange,&Y,&Db,&Dr);
925   if ((fabs(Y-0.783460) >= ReferenceEpsilon) ||
926       (fabs(Db-(-0.480932)) >= ReferenceEpsilon) ||
927       (fabs(Dr-0.451670) >= ReferenceEpsilon))
928     return(MagickFalse);
929   return(MagickTrue);
930 }
931 
ValidateRGBToYIQ()932 static MagickBooleanType ValidateRGBToYIQ()
933 {
934   double
935     i,
936     q,
937     y;
938 
939   (void) FormatLocaleFile(stdout,"  RGBToYIQ");
940   ConvertRGBToYIQ(0.545877*QuantumRange,0.966567*QuantumRange,
941     0.463759*QuantumRange,&y,&i,&q);
942   if ((fabs(y-0.783460) >= ReferenceEpsilon) ||
943       (fabs(i-(-0.089078)) >= ReferenceEpsilon) ||
944       (fabs(q-(-0.245399)) >= ReferenceEpsilon))
945     return(MagickFalse);
946   return(MagickTrue);
947 }
948 
ValidateYIQToRGB()949 static MagickBooleanType ValidateYIQToRGB()
950 {
951   double
952     r,
953     g,
954     b;
955 
956   (void) FormatLocaleFile(stdout,"  YIQToRGB");
957   ConvertYIQToRGB(0.783460,-0.089078+0.5,-0.245399+0.5,&r,&g,&b);
958   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
959       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
960       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
961     return(MagickFalse);
962   return(MagickTrue);
963 }
964 
ValidateRGBToYPbPr()965 static MagickBooleanType ValidateRGBToYPbPr()
966 {
967   double
968     Pb,
969     Pr,
970     y;
971 
972   (void) FormatLocaleFile(stdout,"  RGBToYPbPr");
973   ConvertRGBToYPbPr(0.545877*QuantumRange,0.966567*QuantumRange,
974     0.463759*QuantumRange,&y,&Pb,&Pr);
975   if ((fabs(y-0.783460) >= ReferenceEpsilon) ||
976       (fabs(Pb-(-0.180419)) >= ReferenceEpsilon) ||
977       (fabs(Pr-(-0.169461)) >= ReferenceEpsilon))
978     return(MagickFalse);
979   return(MagickTrue);
980 }
981 
ValidateYPbPrToRGB()982 static MagickBooleanType ValidateYPbPrToRGB()
983 {
984   double
985     r,
986     g,
987     b;
988 
989   (void) FormatLocaleFile(stdout,"  YPbPrToRGB");
990   ConvertYPbPrToRGB(0.783460,-0.180419+0.5,-0.169461+0.5,&r,&g,&b);
991   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
992       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
993       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
994     return(MagickFalse);
995   return(MagickTrue);
996 }
997 
ValidateRGBToYUV()998 static MagickBooleanType ValidateRGBToYUV()
999 {
1000   double
1001     U,
1002     V,
1003     Y;
1004 
1005   (void) FormatLocaleFile(stdout,"  RGBToYUV");
1006   ConvertRGBToYUV(0.545877*QuantumRange,0.966567*QuantumRange,
1007     0.463759*QuantumRange,&Y,&U,&V);
1008   if ((fabs(Y-0.783460) >= ReferenceEpsilon) ||
1009       (fabs(U-(-0.157383)) >= ReferenceEpsilon) ||
1010       (fabs(V-(-0.208443)) >= ReferenceEpsilon))
1011     return(MagickFalse);
1012   return(MagickTrue);
1013 }
1014 
ValidateYUVToRGB()1015 static MagickBooleanType ValidateYUVToRGB()
1016 {
1017   double
1018     r,
1019     g,
1020     b;
1021 
1022   (void) FormatLocaleFile(stdout,"  YUVToRGB");
1023   ConvertYUVToRGB(0.783460,-0.157383+0.5,-0.208443+0.5,&r,&g,&b);
1024   if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
1025       (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
1026       (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
1027     return(MagickFalse);
1028   return(MagickTrue);
1029 }
1030 
ValidateColorspaces(ImageInfo * image_info,size_t * fails,ExceptionInfo * exception)1031 static size_t ValidateColorspaces(ImageInfo *image_info,size_t *fails,
1032   ExceptionInfo *exception)
1033 {
1034   MagickBooleanType
1035     status;
1036 
1037   size_t
1038     fail,
1039     test;
1040 
1041   /*
1042      Reference: https://code.google.com/p/chroma.
1043 
1044      Illuminant =  D65
1045      Observer   =  2° (1931)
1046 
1047      XYZ            0.470645,   0.730177,   0.288323
1048      sRGB           0.545877,   0.966567,   0.463759
1049      CAT02 LMS      0.611749,   0.910088,   0.294880
1050      Y'DbDr         0.783460,  -0.480932,   0.451670
1051      Y'IQ           0.783460,  -0.089078,  -0.245399
1052      Y'PbPr         0.783460,  -0.180419,  -0.169461
1053      Y'UV           0.783460,  -0.157383,  -0.208443
1054      JPEG-Y'CbCr    0.783460,   0.319581,   0.330539
1055      L*u*v*        88.456154, -51.330414,  76.405526
1056      L*a*b*        88.456154, -54.671483,  51.662818
1057      L*C*H*        88.456154,  75.219797, 136.620717
1058      HSV          110.200859,   0.520200,   0.966567
1059      HSL          110.200859,   0.882623,   0.715163
1060      HSI          111.244375,   0.295985,   0.658734
1061      Y'CbCr       187.577791,  87.586330,  90.040886
1062   */
1063   (void) FormatLocaleFile(stdout,"validate colorspaces:\n");
1064   fail=0;
1065   for (test=0; test < 26; test++)
1066   {
1067     CatchException(exception);
1068     (void) FormatLocaleFile(stdout,"  test %.20g: ",(double) test);
1069     switch (test)
1070     {
1071       case  0: status=ValidateHSIToRGB(); break;
1072       case  1: status=ValidateRGBToHSI(); break;
1073       case  2: status=ValidateHSLToRGB(); break;
1074       case  3: status=ValidateRGBToHSL(); break;
1075       case  4: status=ValidateHSVToRGB(); break;
1076       case  5: status=ValidateRGBToHSV(); break;
1077       case  6: status=ValidateJPEGYCbCrToRGB(); break;
1078       case  7: status=ValidateRGBToJPEGYCbCr(); break;
1079       case  8: status=ValidateLabToRGB(); break;
1080       case  9: status=ValidateRGBToLab(); break;
1081       case 10: status=ValidateLchToRGB(); break;
1082       case 11: status=ValidateRGBToLch(); break;
1083       case 12: status=ValidateLMSToRGB(); break;
1084       case 13: status=ValidateRGBToLMS(); break;
1085       case 14: status=ValidateLuvToRGB(); break;
1086       case 15: status=ValidateRGBToLuv(); break;
1087       case 16: status=ValidateXYZToRGB(); break;
1088       case 17: status=ValidateRGBToXYZ(); break;
1089       case 18: status=ValidateYDbDrToRGB(); break;
1090       case 19: status=ValidateRGBToYDbDr(); break;
1091       case 20: status=ValidateYIQToRGB(); break;
1092       case 21: status=ValidateRGBToYIQ(); break;
1093       case 22: status=ValidateYPbPrToRGB(); break;
1094       case 23: status=ValidateRGBToYPbPr(); break;
1095       case 24: status=ValidateYUVToRGB(); break;
1096       case 25: status=ValidateRGBToYUV(); break;
1097       default: status=MagickFalse;
1098     }
1099     if (status == MagickFalse)
1100       {
1101         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1102           GetMagickModule());
1103         fail++;
1104         continue;
1105       }
1106     (void) FormatLocaleFile(stdout,"... pass.\n");
1107   }
1108   (void) FormatLocaleFile(stdout,
1109     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1110     (double) (test-fail),(double) fail);
1111   *fails+=fail;
1112   return(test);
1113 }
1114 
1115 /*
1116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1117 %                                                                             %
1118 %                                                                             %
1119 %                                                                             %
1120 %   V a l i d a t e C o m p a r e C o m m a n d                               %
1121 %                                                                             %
1122 %                                                                             %
1123 %                                                                             %
1124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125 %
1126 %  ValidateCompareCommand() validates the ImageMagick compare command line
1127 %  program and returns the number of validation tests that passed and failed.
1128 %
1129 %  The format of the ValidateCompareCommand method is:
1130 %
1131 %      size_t ValidateCompareCommand(ImageInfo *image_info,
1132 %        const char *reference_filename,const char *output_filename,
1133 %        size_t *fails,ExceptionInfo *exception)
1134 %
1135 %  A description of each parameter follows:
1136 %
1137 %    o image_info: the image info.
1138 %
1139 %    o reference_filename: the reference image filename.
1140 %
1141 %    o output_filename: the output image filename.
1142 %
1143 %    o fail: return the number of validation tests that pass.
1144 %
1145 %    o exception: return any errors or warnings in this structure.
1146 %
1147 */
ValidateCompareCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)1148 static size_t ValidateCompareCommand(ImageInfo *image_info,
1149   const char *reference_filename,const char *output_filename,size_t *fails,
1150   ExceptionInfo *exception)
1151 {
1152   char
1153     **arguments,
1154     command[MagickPathExtent];
1155 
1156   int
1157     number_arguments;
1158 
1159   MagickBooleanType
1160     status;
1161 
1162   ssize_t
1163     i,
1164     j;
1165 
1166   size_t
1167     fail,
1168     test;
1169 
1170   fail=0;
1171   test=0;
1172   (void) FormatLocaleFile(stdout,"validate compare command line program:\n");
1173   for (i=0; compare_options[i] != (char *) NULL; i++)
1174   {
1175     CatchException(exception);
1176     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
1177       compare_options[i]);
1178     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s %s",
1179       compare_options[i],reference_filename,reference_filename,output_filename);
1180     arguments=StringToArgv(command,&number_arguments);
1181     if (arguments == (char **) NULL)
1182       {
1183         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1184           GetMagickModule());
1185         (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),"%s",
1186           exception->reason);
1187         fail++;
1188         continue;
1189       }
1190     status=CompareImagesCommand(image_info,number_arguments,arguments,
1191       (char **) NULL,exception);
1192     for (j=0; j < (ssize_t) number_arguments; j++)
1193       arguments[j]=DestroyString(arguments[j]);
1194     arguments=(char **) RelinquishMagickMemory(arguments);
1195     if (status == MagickFalse)
1196       {
1197         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1198           GetMagickModule());
1199         (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),"%s",
1200           exception->reason);
1201         fail++;
1202         continue;
1203       }
1204     (void) FormatLocaleFile(stdout,"... pass.\n");
1205   }
1206   (void) FormatLocaleFile(stdout,
1207     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1208     (double) (test-fail),(double) fail);
1209   *fails+=fail;
1210   return(test);
1211 }
1212 
1213 /*
1214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215 %                                                                             %
1216 %                                                                             %
1217 %                                                                             %
1218 %   V a l i d a t e C o m p o s i t e C o m m a n d                           %
1219 %                                                                             %
1220 %                                                                             %
1221 %                                                                             %
1222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1223 %
1224 %  ValidateCompositeCommand() validates the ImageMagick composite command line
1225 %  program and returns the number of validation tests that passed and failed.
1226 %
1227 %  The format of the ValidateCompositeCommand method is:
1228 %
1229 %      size_t ValidateCompositeCommand(ImageInfo *image_info,
1230 %        const char *reference_filename,const char *output_filename,
1231 %        size_t *fails,ExceptionInfo *exception)
1232 %
1233 %  A description of each parameter follows:
1234 %
1235 %    o image_info: the image info.
1236 %
1237 %    o reference_filename: the reference image filename.
1238 %
1239 %    o output_filename: the output image filename.
1240 %
1241 %    o fail: return the number of validation tests that pass.
1242 %
1243 %    o exception: return any errors or warnings in this structure.
1244 %
1245 */
ValidateCompositeCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)1246 static size_t ValidateCompositeCommand(ImageInfo *image_info,
1247   const char *reference_filename,const char *output_filename,size_t *fails,
1248   ExceptionInfo *exception)
1249 {
1250   char
1251     **arguments,
1252     command[MagickPathExtent];
1253 
1254   int
1255     number_arguments;
1256 
1257   MagickBooleanType
1258     status;
1259 
1260   ssize_t
1261     i,
1262     j;
1263 
1264   size_t
1265     fail,
1266     test;
1267 
1268   fail=0;
1269   test=0;
1270   (void) FormatLocaleFile(stdout,"validate composite command line program:\n");
1271   for (i=0; composite_options[i] != (char *) NULL; i++)
1272   {
1273     CatchException(exception);
1274     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
1275       composite_options[i]);
1276     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s %s",
1277       reference_filename,composite_options[i],reference_filename,
1278       output_filename);
1279     arguments=StringToArgv(command,&number_arguments);
1280     if (arguments == (char **) NULL)
1281       {
1282         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1283           GetMagickModule());
1284         fail++;
1285         continue;
1286       }
1287     status=CompositeImageCommand(image_info,number_arguments,arguments,
1288       (char **) NULL,exception);
1289     for (j=0; j < (ssize_t) number_arguments; j++)
1290       arguments[j]=DestroyString(arguments[j]);
1291     arguments=(char **) RelinquishMagickMemory(arguments);
1292     if (status == MagickFalse)
1293       {
1294         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1295           GetMagickModule());
1296         fail++;
1297         continue;
1298       }
1299     (void) FormatLocaleFile(stdout,"... pass.\n");
1300   }
1301   (void) FormatLocaleFile(stdout,
1302     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1303     (double) (test-fail),(double) fail);
1304   *fails+=fail;
1305   return(test);
1306 }
1307 
1308 /*
1309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310 %                                                                             %
1311 %                                                                             %
1312 %                                                                             %
1313 %   V a l i d a t e C o n v e r t C o m m a n d                               %
1314 %                                                                             %
1315 %                                                                             %
1316 %                                                                             %
1317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1318 %
1319 %  ValidateConvertCommand() validates the ImageMagick convert command line
1320 %  program and returns the number of validation tests that passed and failed.
1321 %
1322 %  The format of the ValidateConvertCommand method is:
1323 %
1324 %      size_t ValidateConvertCommand(ImageInfo *image_info,
1325 %        const char *reference_filename,const char *output_filename,
1326 %        size_t *fails,ExceptionInfo *exception)
1327 %
1328 %  A description of each parameter follows:
1329 %
1330 %    o image_info: the image info.
1331 %
1332 %    o reference_filename: the reference image filename.
1333 %
1334 %    o output_filename: the output image filename.
1335 %
1336 %    o fail: return the number of validation tests that pass.
1337 %
1338 %    o exception: return any errors or warnings in this structure.
1339 %
1340 */
ValidateConvertCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)1341 static size_t ValidateConvertCommand(ImageInfo *image_info,
1342   const char *reference_filename,const char *output_filename,size_t *fails,
1343   ExceptionInfo *exception)
1344 {
1345   char
1346     **arguments,
1347     command[MagickPathExtent];
1348 
1349   int
1350     number_arguments;
1351 
1352   MagickBooleanType
1353     status;
1354 
1355   ssize_t
1356     i,
1357     j;
1358 
1359   size_t
1360     fail,
1361     test;
1362 
1363   fail=0;
1364   test=0;
1365   (void) FormatLocaleFile(stdout,"validate convert command line program:\n");
1366   for (i=0; convert_options[i] != (char *) NULL; i++)
1367   {
1368     CatchException(exception);
1369     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) test++,
1370       convert_options[i]);
1371     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s %s",
1372       reference_filename,convert_options[i],reference_filename,output_filename);
1373     arguments=StringToArgv(command,&number_arguments);
1374     if (arguments == (char **) NULL)
1375       {
1376         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1377           GetMagickModule());
1378         fail++;
1379         continue;
1380       }
1381     status=ConvertImageCommand(image_info,number_arguments,arguments,
1382       (char **) NULL,exception);
1383     for (j=0; j < (ssize_t) number_arguments; j++)
1384       arguments[j]=DestroyString(arguments[j]);
1385     arguments=(char **) RelinquishMagickMemory(arguments);
1386     if (status == MagickFalse)
1387       {
1388         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1389           GetMagickModule());
1390         fail++;
1391         continue;
1392       }
1393     (void) FormatLocaleFile(stdout,"... pass.\n");
1394   }
1395   (void) FormatLocaleFile(stdout,
1396     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1397     (double) (test-fail),(double) fail);
1398   *fails+=fail;
1399   return(test);
1400 }
1401 
1402 /*
1403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404 %                                                                             %
1405 %                                                                             %
1406 %                                                                             %
1407 %   V a l i d a t e I d e n t i f y C o m m a n d                             %
1408 %                                                                             %
1409 %                                                                             %
1410 %                                                                             %
1411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412 %
1413 %  ValidateIdentifyCommand() validates the ImageMagick identify command line
1414 %  program and returns the number of validation tests that passed and failed.
1415 %
1416 %  The format of the ValidateIdentifyCommand method is:
1417 %
1418 %      size_t ValidateIdentifyCommand(ImageInfo *image_info,
1419 %        const char *reference_filename,const char *output_filename,
1420 %        size_t *fails,ExceptionInfo *exception)
1421 %
1422 %  A description of each parameter follows:
1423 %
1424 %    o image_info: the image info.
1425 %
1426 %    o reference_filename: the reference image filename.
1427 %
1428 %    o output_filename: the output image filename.
1429 %
1430 %    o fail: return the number of validation tests that pass.
1431 %
1432 %    o exception: return any errors or warnings in this structure.
1433 %
1434 */
ValidateIdentifyCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)1435 static size_t ValidateIdentifyCommand(ImageInfo *image_info,
1436   const char *reference_filename,const char *output_filename,size_t *fails,
1437   ExceptionInfo *exception)
1438 {
1439   char
1440     **arguments,
1441     command[MagickPathExtent];
1442 
1443   int
1444     number_arguments;
1445 
1446   MagickBooleanType
1447     status;
1448 
1449   ssize_t
1450     i,
1451     j;
1452 
1453   size_t
1454     fail,
1455     test;
1456 
1457   (void) output_filename;
1458   fail=0;
1459   test=0;
1460   (void) FormatLocaleFile(stdout,"validate identify command line program:\n");
1461   for (i=0; identify_options[i] != (char *) NULL; i++)
1462   {
1463     CatchException(exception);
1464     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) test++,
1465       identify_options[i]);
1466     (void) FormatLocaleString(command,MagickPathExtent,"%s %s",
1467       identify_options[i],reference_filename);
1468     arguments=StringToArgv(command,&number_arguments);
1469     if (arguments == (char **) NULL)
1470       {
1471         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1472           GetMagickModule());
1473         fail++;
1474         continue;
1475       }
1476     status=IdentifyImageCommand(image_info,number_arguments,arguments,
1477       (char **) NULL,exception);
1478     for (j=0; j < (ssize_t) number_arguments; j++)
1479       arguments[j]=DestroyString(arguments[j]);
1480     arguments=(char **) RelinquishMagickMemory(arguments);
1481     if (status == MagickFalse)
1482       {
1483         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1484           GetMagickModule());
1485         fail++;
1486         continue;
1487       }
1488     (void) FormatLocaleFile(stdout,"... pass.\n");
1489   }
1490   (void) FormatLocaleFile(stdout,
1491     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1492     (double) (test-fail),(double) fail);
1493   *fails+=fail;
1494   return(test);
1495 }
1496 
1497 /*
1498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1499 %                                                                             %
1500 %                                                                             %
1501 %                                                                             %
1502 %   V a l i d a t e I m a g e F o r m a t s I n M e m o r y                   %
1503 %                                                                             %
1504 %                                                                             %
1505 %                                                                             %
1506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1507 %
1508 %  ValidateImageFormatsInMemory() validates the ImageMagick image formats in
1509 %  memory and returns the number of validation tests that passed and failed.
1510 %
1511 %  The format of the ValidateImageFormatsInMemory method is:
1512 %
1513 %      size_t ValidateImageFormatsInMemory(ImageInfo *image_info,
1514 %        const char *reference_filename,const char *output_filename,
1515 %        size_t *fails,ExceptionInfo *exception)
1516 %
1517 %  A description of each parameter follows:
1518 %
1519 %    o image_info: the image info.
1520 %
1521 %    o reference_filename: the reference image filename.
1522 %
1523 %    o output_filename: the output image filename.
1524 %
1525 %    o fail: return the number of validation tests that pass.
1526 %
1527 %    o exception: return any errors or warnings in this structure.
1528 %
1529 */
1530 
1531 /*
1532   Enable this to count remaining $TMPDIR/magick-* files.  Note that the count
1533   includes any files left over from other runs.
1534 */
1535 #undef MagickCountTempFiles
1536 
ValidateImageFormatsInMemory(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)1537 static size_t ValidateImageFormatsInMemory(ImageInfo *image_info,
1538   const char *reference_filename,const char *output_filename,size_t *fails,
1539   ExceptionInfo *exception)
1540 {
1541   char
1542 #ifdef MagickCountTempFiles
1543     path[MagickPathExtent],
1544     SystemCommand[MagickPathExtent],
1545 #endif
1546     size[MagickPathExtent];
1547 
1548   const MagickInfo
1549     *magick_info;
1550 
1551   double
1552     distortion,
1553     fuzz;
1554 
1555   Image
1556     *difference_image,
1557     *ping_image,
1558     *reconstruct_image,
1559     *reference_image;
1560 
1561   MagickBooleanType
1562     status;
1563 
1564   ssize_t
1565     i,
1566     j;
1567 
1568   size_t
1569     fail,
1570     length,
1571     test;
1572 
1573   unsigned char
1574     *blob;
1575 
1576   fail=0;
1577   test=0;
1578   (void) FormatLocaleFile(stdout,"validate image formats in memory:\n");
1579 
1580 #ifdef MagickCountTempFiles
1581   (void)GetPathTemplate(path);
1582   /* Remove file template except for the leading "/path/to/magick-" */
1583   path[strlen(path)-17]='\0';
1584   (void) FormatLocaleFile(stdout," tmp path is '%s*'\n",path);
1585 #endif
1586 
1587   for (i=0; reference_formats[i].magick != (char *) NULL; i++)
1588   {
1589     magick_info=GetMagickInfo(reference_formats[i].magick,exception);
1590     if ((magick_info == (const MagickInfo *) NULL) ||
1591         (magick_info->decoder == (DecodeImageHandler *) NULL) ||
1592         (magick_info->encoder == (EncodeImageHandler *) NULL))
1593       continue;
1594     for (j=0; reference_types[j].type != UndefinedType; j++)
1595     {
1596       /*
1597         Generate reference image.
1598       */
1599       CatchException(exception);
1600       (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
1601         (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
1602         MagickCompressOptions,reference_formats[i].compression),
1603         CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
1604         (double) reference_types[j].depth);
1605       (void) CopyMagickString(image_info->filename,reference_filename,
1606         MagickPathExtent);
1607       reference_image=ReadImage(image_info,exception);
1608       if ((reference_image == (Image *) NULL) ||
1609           (exception->severity >= ErrorException))
1610         {
1611           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1612             GetMagickModule());
1613           if (exception->reason != (char *) NULL)
1614             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1615           CatchException(exception);
1616           fail++;
1617           continue;
1618         }
1619       /*
1620         Write reference image.
1621       */
1622       (void) FormatLocaleString(size,MagickPathExtent,"%.20gx%.20g",
1623         (double) reference_image->columns,(double) reference_image->rows);
1624       (void) CloneString(&image_info->size,size);
1625       image_info->depth=reference_types[j].depth;
1626       (void) FormatLocaleString(reference_image->filename,MagickPathExtent,
1627         "%s:%s",reference_formats[i].magick,output_filename);
1628       status=SetImageType(reference_image,reference_types[j].type,exception);
1629       if (status == MagickFalse || (exception->severity >= ErrorException))
1630         {
1631           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1632             GetMagickModule());
1633           if (exception->reason != (char *) NULL)
1634             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1635           CatchException(exception);
1636           fail++;
1637           reference_image=DestroyImage(reference_image);
1638           continue;
1639         }
1640       status=SetImageDepth(reference_image,reference_types[j].depth,exception);
1641       if (status == MagickFalse || (exception->severity >= ErrorException))
1642         {
1643           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1644             GetMagickModule());
1645           CatchException(exception);
1646           fail++;
1647           reference_image=DestroyImage(reference_image);
1648           continue;
1649         }
1650       reference_image->compression=reference_formats[i].compression;
1651       status=WriteImage(image_info,reference_image,exception);
1652       reference_image=DestroyImage(reference_image);
1653       if (status == MagickFalse || (exception->severity >= ErrorException))
1654         {
1655           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1656             GetMagickModule());
1657           if (exception->reason != (char *) NULL)
1658             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1659           CatchException(exception);
1660           fail++;
1661           continue;
1662         }
1663       /*
1664         Ping reference image.
1665       */
1666       (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s:%s",
1667         reference_formats[i].magick,output_filename);
1668       ping_image=PingImage(image_info,exception);
1669       if (ping_image == (Image *) NULL ||
1670           (exception->severity >= ErrorException))
1671         {
1672           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1673             GetMagickModule());
1674           if (exception->reason != (char *) NULL)
1675             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1676           CatchException(exception);
1677           fail++;
1678           continue;
1679         }
1680       ping_image=DestroyImage(ping_image);
1681       /*
1682         Read reference image.
1683       */
1684       reference_image=ReadImage(image_info,exception);
1685       if ((reference_image == (Image *) NULL) ||
1686           (exception->severity >= ErrorException))
1687         {
1688           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1689             GetMagickModule());
1690           if (exception->reason != (char *) NULL)
1691             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1692           CatchException(exception);
1693           fail++;
1694           continue;
1695         }
1696       /*
1697         Write reference image.
1698       */
1699       (void) FormatLocaleString(reference_image->filename,MagickPathExtent,
1700         "%s:%s",reference_formats[i].magick,output_filename);
1701       (void) CopyMagickString(image_info->magick,reference_formats[i].magick,
1702         MagickPathExtent);
1703       reference_image->depth=reference_types[j].depth;
1704       reference_image->compression=reference_formats[i].compression;
1705       length=8192;
1706       blob=(unsigned char *) ImageToBlob(image_info,reference_image,&length,
1707         exception);
1708       if ((blob == (unsigned char *) NULL) ||
1709           (exception->severity >= ErrorException))
1710         {
1711           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1712             GetMagickModule());
1713           if (exception->reason != (char *) NULL)
1714             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1715           CatchException(exception);
1716           fail++;
1717           reference_image=DestroyImage(reference_image);
1718           continue;
1719         }
1720       /*
1721         Ping reference blob.
1722       */
1723       ping_image=PingBlob(image_info,blob,length,exception);
1724       if (ping_image == (Image *) NULL ||
1725           (exception->severity >= ErrorException))
1726         {
1727           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1728             GetMagickModule());
1729           if (exception->reason != (char *) NULL)
1730             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1731           CatchException(exception);
1732           fail++;
1733           blob=(unsigned char *) RelinquishMagickMemory(blob);
1734           continue;
1735         }
1736       ping_image=DestroyImage(ping_image);
1737       /*
1738         Read reconstruct image.
1739       */
1740       (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s:%s",
1741         reference_formats[i].magick,output_filename);
1742       reconstruct_image=BlobToImage(image_info,blob,length,exception);
1743       blob=(unsigned char *) RelinquishMagickMemory(blob);
1744       if (reconstruct_image == (Image *) NULL ||
1745           (exception->severity >= ErrorException))
1746         {
1747           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1748             GetMagickModule());
1749           if (exception->reason != (char *) NULL)
1750             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1751           CatchException(exception);
1752           fail++;
1753           reference_image=DestroyImage(reference_image);
1754           continue;
1755         }
1756       /*
1757         Compare reference to reconstruct image.
1758       */
1759       fuzz=0.003;  /* grayscale */
1760       if (reference_formats[i].fuzz != 0.0)
1761         fuzz=reference_formats[i].fuzz;
1762       difference_image=CompareImages(reference_image,reconstruct_image,
1763         RootMeanSquaredErrorMetric,&distortion,exception);
1764       reconstruct_image=DestroyImage(reconstruct_image);
1765       reference_image=DestroyImage(reference_image);
1766       if (difference_image == (Image *) NULL ||
1767           (exception->severity >= ErrorException))
1768         {
1769           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1770             GetMagickModule());
1771           if (exception->reason != (char *) NULL)
1772             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1773           CatchException(exception);
1774           fail++;
1775           continue;
1776         }
1777       difference_image=DestroyImage(difference_image);
1778       if ((QuantumScale*distortion) > fuzz)
1779         {
1780           (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
1781             QuantumScale*distortion);
1782           fail++;
1783           continue;
1784         }
1785 #ifdef MagickCountTempFiles
1786       (void) FormatLocaleFile(stdout,"... pass, ");
1787       (void) fflush(stdout);
1788       SystemCommand[0]='\0';
1789       (void) strncat(SystemCommand,"echo `ls ",9);
1790       (void) strncat(SystemCommand,path,MagickPathExtent-31);
1791       (void) strncat(SystemCommand,"* | wc -w` tmp files.",20);
1792       (void) system(SystemCommand);
1793       (void) fflush(stdout);
1794 #else
1795       (void) FormatLocaleFile(stdout,"... pass\n");
1796 #endif
1797     }
1798   }
1799   (void) FormatLocaleFile(stdout,
1800     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1801     (double) (test-fail),(double) fail);
1802   *fails+=fail;
1803   return(test);
1804 }
1805 
1806 /*
1807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1808 %                                                                             %
1809 %                                                                             %
1810 %                                                                             %
1811 %   V a l i d a t e I m a g e F o r m a t s O n D i s k                       %
1812 %                                                                             %
1813 %                                                                             %
1814 %                                                                             %
1815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1816 %
1817 %  ValidateImageFormatsOnDisk() validates the ImageMagick image formats on disk
1818 %  and returns the number of validation tests that passed and failed.
1819 %
1820 %  The format of the ValidateImageFormatsOnDisk method is:
1821 %
1822 %      size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
1823 %        const char *reference_filename,const char *output_filename,
1824 %        size_t *fails,ExceptionInfo *exception)
1825 %
1826 %  A description of each parameter follows:
1827 %
1828 %    o image_info: the image info.
1829 %
1830 %    o reference_filename: the reference image filename.
1831 %
1832 %    o output_filename: the output image filename.
1833 %
1834 %    o fail: return the number of validation tests that pass.
1835 %
1836 %    o exception: return any errors or warnings in this structure.
1837 %
1838 */
ValidateImageFormatsOnDisk(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)1839 static size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
1840   const char *reference_filename,const char *output_filename,size_t *fails,
1841   ExceptionInfo *exception)
1842 {
1843   char
1844     size[MagickPathExtent];
1845 
1846   const MagickInfo
1847     *magick_info;
1848 
1849   double
1850     distortion,
1851     fuzz;
1852 
1853   Image
1854     *difference_image,
1855     *reference_image,
1856     *reconstruct_image;
1857 
1858   MagickBooleanType
1859     status;
1860 
1861   ssize_t
1862     i,
1863     j;
1864 
1865   size_t
1866     fail,
1867     test;
1868 
1869   fail=0;
1870   test=0;
1871   (void) FormatLocaleFile(stdout,"validate image formats on disk:\n");
1872   for (i=0; reference_formats[i].magick != (char *) NULL; i++)
1873   {
1874     magick_info=GetMagickInfo(reference_formats[i].magick,exception);
1875     if ((magick_info == (const MagickInfo *) NULL) ||
1876         (magick_info->decoder == (DecodeImageHandler *) NULL) ||
1877         (magick_info->encoder == (EncodeImageHandler *) NULL))
1878       continue;
1879     for (j=0; reference_types[j].type != UndefinedType; j++)
1880     {
1881       /*
1882         Generate reference image.
1883       */
1884       CatchException(exception);
1885       (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
1886         (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
1887         MagickCompressOptions,reference_formats[i].compression),
1888         CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
1889         (double) reference_types[j].depth);
1890       (void) CopyMagickString(image_info->filename,reference_filename,
1891         MagickPathExtent);
1892       reference_image=ReadImage(image_info,exception);
1893       if ((reference_image == (Image *) NULL) ||
1894           (exception->severity >= ErrorException))
1895         {
1896           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1897             GetMagickModule());
1898           if (exception->reason != (char *) NULL)
1899             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1900           CatchException(exception);
1901           fail++;
1902           continue;
1903         }
1904       /*
1905         Write reference image.
1906       */
1907       (void) FormatLocaleString(size,MagickPathExtent,"%.20gx%.20g",
1908         (double) reference_image->columns,(double) reference_image->rows);
1909       (void) CloneString(&image_info->size,size);
1910       image_info->depth=reference_types[j].depth;
1911       (void) FormatLocaleString(reference_image->filename,MagickPathExtent,
1912         "%s:%s",reference_formats[i].magick,output_filename);
1913       status=SetImageType(reference_image,reference_types[j].type,exception);
1914       if (status == MagickFalse || (exception->severity >= ErrorException))
1915         {
1916           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1917             GetMagickModule());
1918           if (exception->reason != (char *) NULL)
1919             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1920           CatchException(exception);
1921           fail++;
1922           reference_image=DestroyImage(reference_image);
1923           continue;
1924         }
1925       status=SetImageDepth(reference_image,reference_types[j].depth,exception);
1926       if (status == MagickFalse || (exception->severity >= ErrorException))
1927         {
1928           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1929             GetMagickModule());
1930           CatchException(exception);
1931           fail++;
1932           reference_image=DestroyImage(reference_image);
1933           continue;
1934         }
1935       reference_image->compression=reference_formats[i].compression;
1936       status=WriteImage(image_info,reference_image,exception);
1937       reference_image=DestroyImage(reference_image);
1938       if (status == MagickFalse || (exception->severity >= ErrorException))
1939         {
1940           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1941             GetMagickModule());
1942           if (exception->reason != (char *) NULL)
1943             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1944           CatchException(exception);
1945           fail++;
1946           continue;
1947         }
1948       /*
1949         Read reference image.
1950       */
1951       (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s:%s",
1952         reference_formats[i].magick,output_filename);
1953       reference_image=ReadImage(image_info,exception);
1954       if ((reference_image == (Image *) NULL) ||
1955           (exception->severity >= ErrorException))
1956         {
1957           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1958             GetMagickModule());
1959           CatchException(exception);
1960           fail++;
1961           continue;
1962         }
1963       /*
1964         Write reference image.
1965       */
1966       (void) FormatLocaleString(reference_image->filename,MagickPathExtent,
1967         "%s:%s",reference_formats[i].magick,output_filename);
1968       reference_image->depth=reference_types[j].depth;
1969       reference_image->compression=reference_formats[i].compression;
1970       status=WriteImage(image_info,reference_image,exception);
1971       if (status == MagickFalse ||exception->severity >= ErrorException)
1972         {
1973           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1974             GetMagickModule());
1975           CatchException(exception);
1976           fail++;
1977           reference_image=DestroyImage(reference_image);
1978           continue;
1979         }
1980       /*
1981         Read reconstruct image.
1982       */
1983       (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s:%s",
1984         reference_formats[i].magick,output_filename);
1985       reconstruct_image=ReadImage(image_info,exception);
1986       if (reconstruct_image == (Image *) NULL ||
1987           (exception->severity >= ErrorException))
1988         {
1989           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1990             GetMagickModule());
1991           CatchException(exception);
1992           fail++;
1993           reference_image=DestroyImage(reference_image);
1994           continue;
1995         }
1996       /*
1997         Compare reference to reconstruct image.
1998       */
1999       fuzz=0.003;  /* grayscale */
2000       if (reference_formats[i].fuzz != 0.0)
2001         fuzz=reference_formats[i].fuzz;
2002       difference_image=CompareImages(reference_image,reconstruct_image,
2003         RootMeanSquaredErrorMetric,&distortion,exception);
2004       reconstruct_image=DestroyImage(reconstruct_image);
2005       reference_image=DestroyImage(reference_image);
2006       if (difference_image == (Image *) NULL ||
2007           (exception->severity >= ErrorException))
2008         {
2009           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2010             GetMagickModule());
2011           CatchException(exception);
2012           fail++;
2013           continue;
2014         }
2015       difference_image=DestroyImage(difference_image);
2016       if ((QuantumScale*distortion) > fuzz)
2017         {
2018           (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
2019             QuantumScale*distortion);
2020           fail++;
2021           continue;
2022         }
2023       (void) FormatLocaleFile(stdout,"... pass.\n");
2024     }
2025   }
2026   (void) FormatLocaleFile(stdout,
2027     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
2028     (double) (test-fail),(double) fail);
2029   *fails+=fail;
2030   return(test);
2031 }
2032 
2033 /*
2034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2035 %                                                                             %
2036 %                                                                             %
2037 %                                                                             %
2038 %   V a l i d a t e I m p o r t E x p o r t P i x e l s                       %
2039 %                                                                             %
2040 %                                                                             %
2041 %                                                                             %
2042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043 %
2044 %  ValidateImportExportPixels() validates the pixel import and export methods.
2045 %  It returns the number of validation tests that passed and failed.
2046 %
2047 %  The format of the ValidateImportExportPixels method is:
2048 %
2049 %      size_t ValidateImportExportPixels(ImageInfo *image_info,
2050 %        const char *reference_filename,const char *output_filename,
2051 %        size_t *fails,ExceptionInfo *exception)
2052 %
2053 %  A description of each parameter follows:
2054 %
2055 %    o image_info: the image info.
2056 %
2057 %    o reference_filename: the reference image filename.
2058 %
2059 %    o output_filename: the output image filename.
2060 %
2061 %    o fail: return the number of validation tests that pass.
2062 %
2063 %    o exception: return any errors or warnings in this structure.
2064 %
2065 */
ValidateImportExportPixels(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)2066 static size_t ValidateImportExportPixels(ImageInfo *image_info,
2067   const char *reference_filename,const char *output_filename,size_t *fails,
2068   ExceptionInfo *exception)
2069 {
2070   double
2071     distortion;
2072 
2073   Image
2074     *difference_image,
2075     *reference_image,
2076     *reconstruct_image;
2077 
2078   MagickBooleanType
2079     status;
2080 
2081   ssize_t
2082     i,
2083     j;
2084 
2085   size_t
2086     length;
2087 
2088   unsigned char
2089     *pixels;
2090 
2091   size_t
2092     fail,
2093     test;
2094 
2095   (void) output_filename;
2096   fail=0;
2097   test=0;
2098   (void) FormatLocaleFile(stdout,
2099     "validate the import and export of image pixels:\n");
2100   for (i=0; reference_map[i] != (char *) NULL; i++)
2101   {
2102     for (j=0; reference_storage[j].type != UndefinedPixel; j++)
2103     {
2104       /*
2105         Generate reference image.
2106       */
2107       CatchException(exception);
2108       (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s",(double) (test++),
2109         reference_map[i],CommandOptionToMnemonic(MagickStorageOptions,
2110         reference_storage[j].type));
2111       (void) CopyMagickString(image_info->filename,reference_filename,
2112         MagickPathExtent);
2113       reference_image=ReadImage(image_info,exception);
2114       if ((reference_image == (Image *) NULL) ||
2115           (exception->severity >= ErrorException))
2116         {
2117           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2118             GetMagickModule());
2119           CatchException(exception);
2120           fail++;
2121           continue;
2122         }
2123       if (LocaleNCompare(reference_map[i],"cmy",3) == 0)
2124         (void) SetImageColorspace(reference_image,CMYKColorspace,exception);
2125       length=strlen(reference_map[i])*reference_image->columns*
2126         reference_image->rows*reference_storage[j].quantum;
2127       pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
2128       if ((pixels == (unsigned char *) NULL) ||
2129           (exception->severity >= ErrorException))
2130         {
2131           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2132             GetMagickModule());
2133           CatchException(exception);
2134           fail++;
2135           reference_image=DestroyImage(reference_image);
2136           continue;
2137         }
2138       (void) memset(pixels,0,length*sizeof(*pixels));
2139       status=ExportImagePixels(reference_image,0,0,reference_image->columns,
2140         reference_image->rows,reference_map[i],reference_storage[j].type,pixels,
2141         exception);
2142       if (status == MagickFalse || (exception->severity >= ErrorException))
2143         {
2144           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2145             GetMagickModule());
2146           CatchException(exception);
2147           fail++;
2148           pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2149           reference_image=DestroyImage(reference_image);
2150           continue;
2151         }
2152       (void) SetImageBackgroundColor(reference_image,exception);
2153       status=ImportImagePixels(reference_image,0,0,reference_image->columns,
2154         reference_image->rows,reference_map[i],reference_storage[j].type,
2155         pixels,exception);
2156       if (status == MagickFalse || (exception->severity >= ErrorException))
2157         {
2158           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2159             GetMagickModule());
2160           CatchException(exception);
2161           fail++;
2162            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2163           reference_image=DestroyImage(reference_image);
2164           continue;
2165         }
2166       /*
2167         Read reconstruct image.
2168       */
2169       reconstruct_image=AcquireImage(image_info,exception);
2170       (void) SetImageExtent(reconstruct_image,reference_image->columns,
2171         reference_image->rows,exception);
2172       (void) SetImageColorspace(reconstruct_image,reference_image->colorspace,
2173         exception);
2174       (void) SetImageBackgroundColor(reconstruct_image,exception);
2175       status=ImportImagePixels(reconstruct_image,0,0,reconstruct_image->columns,
2176         reconstruct_image->rows,reference_map[i],reference_storage[j].type,
2177         pixels,exception);
2178       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2179       if (status == MagickFalse || (exception->severity >= ErrorException))
2180         {
2181           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2182             GetMagickModule());
2183           CatchException(exception);
2184           fail++;
2185           reference_image=DestroyImage(reference_image);
2186           continue;
2187         }
2188       /*
2189         Compare reference to reconstruct image.
2190       */
2191       difference_image=CompareImages(reference_image,reconstruct_image,
2192         RootMeanSquaredErrorMetric,&distortion,exception);
2193       reconstruct_image=DestroyImage(reconstruct_image);
2194       reference_image=DestroyImage(reference_image);
2195       if (difference_image == (Image *) NULL ||
2196           (exception->severity >= ErrorException))
2197         {
2198           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2199             GetMagickModule());
2200           CatchException(exception);
2201           fail++;
2202           continue;
2203         }
2204       difference_image=DestroyImage(difference_image);
2205       if ((QuantumScale*distortion) > 0.0)
2206         {
2207           (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
2208             QuantumScale*distortion);
2209           fail++;
2210           continue;
2211         }
2212       (void) FormatLocaleFile(stdout,"... pass.\n");
2213     }
2214   }
2215   (void) FormatLocaleFile(stdout,
2216     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
2217     (double) (test-fail),(double) fail);
2218   *fails+=fail;
2219   return(test);
2220 }
2221 
2222 /*
2223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2224 %                                                                             %
2225 %                                                                             %
2226 %                                                                             %
2227 %   V a l i d a t e M o n t a g e C o m m a n d                               %
2228 %                                                                             %
2229 %                                                                             %
2230 %                                                                             %
2231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2232 %
2233 %  ValidateMontageCommand() validates the ImageMagick montage command line
2234 %  program and returns the number of validation tests that passed and failed.
2235 %
2236 %  The format of the ValidateMontageCommand method is:
2237 %
2238 %      size_t ValidateMontageCommand(ImageInfo *image_info,
2239 %        const char *reference_filename,const char *output_filename,
2240 %        size_t *fails,ExceptionInfo *exception)
2241 %
2242 %  A description of each parameter follows:
2243 %
2244 %    o image_info: the image info.
2245 %
2246 %    o reference_filename: the reference image filename.
2247 %
2248 %    o output_filename: the output image filename.
2249 %
2250 %    o fail: return the number of validation tests that pass.
2251 %
2252 %    o exception: return any errors or warnings in this structure.
2253 %
2254 */
ValidateMontageCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)2255 static size_t ValidateMontageCommand(ImageInfo *image_info,
2256   const char *reference_filename,const char *output_filename,size_t *fails,
2257   ExceptionInfo *exception)
2258 {
2259   char
2260     **arguments,
2261     command[MagickPathExtent];
2262 
2263   int
2264     number_arguments;
2265 
2266   MagickBooleanType
2267     status;
2268 
2269   ssize_t
2270     i,
2271     j;
2272 
2273   size_t
2274     fail,
2275     test;
2276 
2277   fail=0;
2278   test=0;
2279   (void) FormatLocaleFile(stdout,"validate montage command line program:\n");
2280   for (i=0; montage_options[i] != (char *) NULL; i++)
2281   {
2282     CatchException(exception);
2283     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
2284       montage_options[i]);
2285     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s %s",
2286       reference_filename,montage_options[i],reference_filename,
2287       output_filename);
2288     arguments=StringToArgv(command,&number_arguments);
2289     if (arguments == (char **) NULL)
2290       {
2291         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2292             GetMagickModule());
2293         fail++;
2294         continue;
2295       }
2296     status=MontageImageCommand(image_info,number_arguments,arguments,
2297       (char **) NULL,exception);
2298     for (j=0; j < (ssize_t) number_arguments; j++)
2299       arguments[j]=DestroyString(arguments[j]);
2300     arguments=(char **) RelinquishMagickMemory(arguments);
2301     if (status == MagickFalse)
2302       {
2303         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2304             GetMagickModule());
2305         fail++;
2306         continue;
2307       }
2308     (void) FormatLocaleFile(stdout,"... pass.\n");
2309   }
2310   (void) FormatLocaleFile(stdout,
2311     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
2312     (double) (test-fail),(double) fail);
2313   *fails+=fail;
2314   return(test);
2315 }
2316 
2317 /*
2318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319 %                                                                             %
2320 %                                                                             %
2321 %                                                                             %
2322 %   V a l i d a t e S t r e a m C o m m a n d                                 %
2323 %                                                                             %
2324 %                                                                             %
2325 %                                                                             %
2326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327 %
2328 %  ValidateStreamCommand() validates the ImageMagick stream command line
2329 %  program and returns the number of validation tests that passed and failed.
2330 %
2331 %  The format of the ValidateStreamCommand method is:
2332 %
2333 %      size_t ValidateStreamCommand(ImageInfo *image_info,
2334 %        const char *reference_filename,const char *output_filename,
2335 %        size_t *fails,ExceptionInfo *exception)
2336 %
2337 %  A description of each parameter follows:
2338 %
2339 %    o image_info: the image info.
2340 %
2341 %    o reference_filename: the reference image filename.
2342 %
2343 %    o output_filename: the output image filename.
2344 %
2345 %    o fail: return the number of validation tests that pass.
2346 %
2347 %    o exception: return any errors or warnings in this structure.
2348 %
2349 */
ValidateStreamCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fails,ExceptionInfo * exception)2350 static size_t ValidateStreamCommand(ImageInfo *image_info,
2351   const char *reference_filename,const char *output_filename,size_t *fails,
2352   ExceptionInfo *exception)
2353 {
2354   char
2355     **arguments,
2356     command[MagickPathExtent];
2357 
2358   int
2359     number_arguments;
2360 
2361   MagickBooleanType
2362     status;
2363 
2364   ssize_t
2365     i,
2366     j;
2367 
2368   size_t
2369     fail,
2370     test;
2371 
2372   fail=0;
2373   test=0;
2374   (void) FormatLocaleFile(stdout,"validate stream command line program:\n");
2375   for (i=0; stream_options[i] != (char *) NULL; i++)
2376   {
2377     CatchException(exception);
2378     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
2379       stream_options[i]);
2380     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s",
2381       stream_options[i],reference_filename,output_filename);
2382     arguments=StringToArgv(command,&number_arguments);
2383     if (arguments == (char **) NULL)
2384       {
2385         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2386           GetMagickModule());
2387         fail++;
2388         continue;
2389       }
2390     status=StreamImageCommand(image_info,number_arguments,arguments,
2391       (char **) NULL,exception);
2392     for (j=0; j < (ssize_t) number_arguments; j++)
2393       arguments[j]=DestroyString(arguments[j]);
2394     arguments=(char **) RelinquishMagickMemory(arguments);
2395     if (status == MagickFalse)
2396       {
2397         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2398           GetMagickModule());
2399         fail++;
2400         continue;
2401       }
2402     (void) FormatLocaleFile(stdout,"... pass.\n");
2403   }
2404   (void) FormatLocaleFile(stdout,
2405     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
2406     (double) (test-fail),(double) fail);
2407   *fails+=fail;
2408   return(test);
2409 }
2410 
2411 /*
2412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413 %                                                                             %
2414 %                                                                             %
2415 %                                                                             %
2416 %  M a i n                                                                    %
2417 %                                                                             %
2418 %                                                                             %
2419 %                                                                             %
2420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2421 %
2422 %
2423 */
2424 
ValidateUsage(void)2425 static MagickBooleanType ValidateUsage(void)
2426 {
2427   const char
2428     **p;
2429 
2430   static const char
2431     *miscellaneous[]=
2432     {
2433       "-debug events        display copious debugging information",
2434       "-help                print program options",
2435       "-log format          format of debugging information",
2436       "-validate type       validation type",
2437       "-version             print version information",
2438       (char *) NULL
2439     },
2440     *settings[]=
2441     {
2442       "-regard-warnings     pay attention to warning messages",
2443       "-verbose             print detailed information about the image",
2444       (char *) NULL
2445     };
2446 
2447   (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
2448   (void) printf("Copyright: %s\n\n",GetMagickCopyright());
2449   (void) printf("Features: %s\n",GetMagickFeatures());
2450   (void) printf("Usage: %s [options ...] reference-file\n",GetClientName());
2451   (void) printf("\nValidate Settings:\n");
2452   for (p=settings; *p != (char *) NULL; p++)
2453     (void) printf("  %s\n",*p);
2454   (void) printf("\nMiscellaneous Options:\n");
2455   for (p=miscellaneous; *p != (char *) NULL; p++)
2456     (void) printf("  %s\n",*p);
2457   return(MagickTrue);
2458 }
2459 
main(int argc,char ** argv)2460 int main(int argc,char **argv)
2461 {
2462 #define DestroyValidate() \
2463 { \
2464   image_info=DestroyImageInfo(image_info); \
2465   exception=DestroyExceptionInfo(exception); \
2466 }
2467 #define ThrowValidateException(asperity,tag,option) \
2468 { \
2469   (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag,"`%s'", \
2470     option); \
2471   CatchException(exception); \
2472   DestroyValidate(); \
2473   return(MagickFalse); \
2474 }
2475 
2476   char
2477     output_filename[MagickPathExtent],
2478     reference_filename[MagickPathExtent],
2479     *option;
2480 
2481   double
2482     elapsed_time,
2483     user_time;
2484 
2485   ExceptionInfo
2486     *exception;
2487 
2488   Image
2489     *reference_image;
2490 
2491   ImageInfo
2492     *image_info;
2493 
2494   MagickBooleanType
2495     regard_warnings,
2496     status;
2497 
2498   MagickSizeType
2499     memory_resource,
2500     map_resource;
2501 
2502   ssize_t
2503     i;
2504 
2505   TimerInfo
2506     *timer;
2507 
2508   size_t
2509     fail,
2510     iterations,
2511     tests;
2512 
2513   ValidateType
2514     type;
2515 
2516   /*
2517     Validate the ImageMagick image processing suite.
2518   */
2519   MagickCoreGenesis(*argv,MagickTrue);
2520   (void) setlocale(LC_ALL,"");
2521   (void) setlocale(LC_NUMERIC,"C");
2522   iterations=1;
2523   status=MagickFalse;
2524   type=AllValidate;
2525   regard_warnings=MagickFalse;
2526   (void) regard_warnings;
2527   exception=AcquireExceptionInfo();
2528   image_info=AcquireImageInfo();
2529   (void) CopyMagickString(image_info->filename,ReferenceFilename,
2530     MagickPathExtent);
2531   for (i=1; i < (ssize_t) argc; i++)
2532   {
2533     option=argv[i];
2534     if (IsCommandOption(option) == MagickFalse)
2535       {
2536         (void) CopyMagickString(image_info->filename,option,MagickPathExtent);
2537         continue;
2538       }
2539     switch (*(option+1))
2540     {
2541       case 'b':
2542       {
2543         if (LocaleCompare("bench",option+1) == 0)
2544           {
2545             iterations=StringToUnsignedLong(argv[++i]);
2546             break;
2547           }
2548         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2549       }
2550       case 'd':
2551       {
2552         if (LocaleCompare("debug",option+1) == 0)
2553           {
2554             (void) SetLogEventMask(argv[++i]);
2555             break;
2556           }
2557         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2558       }
2559       case 'h':
2560       {
2561         if (LocaleCompare("help",option+1) == 0)
2562           {
2563             (void) ValidateUsage();
2564             return(0);
2565           }
2566         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2567       }
2568       case 'l':
2569       {
2570         if (LocaleCompare("log",option+1) == 0)
2571           {
2572             if (*option != '+')
2573               (void) SetLogFormat(argv[i+1]);
2574             break;
2575           }
2576         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2577       }
2578       case 'r':
2579       {
2580         if (LocaleCompare("regard-warnings",option+1) == 0)
2581           {
2582             regard_warnings=MagickTrue;
2583             break;
2584           }
2585         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2586       }
2587       case 'v':
2588       {
2589         if (LocaleCompare("validate",option+1) == 0)
2590           {
2591             ssize_t
2592               validate;
2593 
2594             if (*option == '+')
2595               break;
2596             i++;
2597             if (i >= (ssize_t) argc)
2598               ThrowValidateException(OptionError,"MissingArgument",option);
2599             validate=ParseCommandOption(MagickValidateOptions,MagickFalse,
2600               argv[i]);
2601             if (validate < 0)
2602               ThrowValidateException(OptionError,"UnrecognizedValidateType",
2603                 argv[i]);
2604             type=(ValidateType) validate;
2605             break;
2606           }
2607         if ((LocaleCompare("version",option+1) == 0) ||
2608             (LocaleCompare("-version",option+1) == 0))
2609           {
2610             (void) FormatLocaleFile(stdout,"Version: %s\n",
2611               GetMagickVersion((size_t *) NULL));
2612             (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
2613               GetMagickCopyright());
2614             (void) FormatLocaleFile(stdout,"Features: %s\n\n",
2615               GetMagickFeatures());
2616             return(0);
2617           }
2618         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2619       }
2620       default:
2621         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2622     }
2623   }
2624   timer=(TimerInfo *) NULL;
2625   if (iterations > 1)
2626     timer=AcquireTimerInfo();
2627   reference_image=ReadImage(image_info,exception);
2628   tests=0;
2629   fail=0;
2630   if (reference_image == (Image *) NULL)
2631     fail++;
2632   else
2633     {
2634       if (LocaleCompare(image_info->filename,ReferenceFilename) == 0)
2635         (void) CopyMagickString(reference_image->magick,ReferenceImageFormat,
2636           MagickPathExtent);
2637       (void) AcquireUniqueFilename(reference_filename);
2638       (void) AcquireUniqueFilename(output_filename);
2639       (void) CopyMagickString(reference_image->filename,reference_filename,
2640         MagickPathExtent);
2641       status=WriteImage(image_info,reference_image,exception);
2642       reference_image=DestroyImage(reference_image);
2643       if (status == MagickFalse)
2644         fail++;
2645       else
2646         {
2647           (void) FormatLocaleFile(stdout,"Version: %s\n",
2648             GetMagickVersion((size_t *) NULL));
2649           (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
2650             GetMagickCopyright());
2651           (void) FormatLocaleFile(stdout,
2652             "ImageMagick Validation Suite (%s)\n\n",CommandOptionToMnemonic(
2653             MagickValidateOptions,(ssize_t) type));
2654           if ((type & ColorspaceValidate) != 0)
2655             tests+=ValidateColorspaces(image_info,&fail,exception);
2656           if ((type & CompareValidate) != 0)
2657             tests+=ValidateCompareCommand(image_info,reference_filename,
2658               output_filename,&fail,exception);
2659           if ((type & CompositeValidate) != 0)
2660             tests+=ValidateCompositeCommand(image_info,reference_filename,
2661               output_filename,&fail,exception);
2662           if ((type & ConvertValidate) != 0)
2663             tests+=ValidateConvertCommand(image_info,reference_filename,
2664               output_filename,&fail,exception);
2665           if ((type & FormatsDiskValidate) != 0)
2666             {
2667               memory_resource=SetMagickResourceLimit(MemoryResource,0);
2668               map_resource=SetMagickResourceLimit(MapResource,0);
2669               (void) FormatLocaleFile(stdout,"[pixel-cache: disk] ");
2670               tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
2671                 output_filename,&fail,exception);
2672               (void) FormatLocaleFile(stdout,"[pixel-cache: disk] ");
2673               tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
2674                 output_filename,&fail,exception);
2675               (void) SetMagickResourceLimit(MemoryResource,memory_resource);
2676               (void) SetMagickResourceLimit(MapResource,map_resource);
2677             }
2678           if ((type & FormatsMapValidate) != 0)
2679             {
2680               memory_resource=SetMagickResourceLimit(MemoryResource,0);
2681               (void) FormatLocaleFile(stdout,"[pixel-cache: memory-mapped] ");
2682               tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
2683                 output_filename,&fail,exception);
2684               (void) FormatLocaleFile(stdout,"[pixel-cache: memory-mapped] ");
2685               tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
2686                 output_filename,&fail,exception);
2687               (void) SetMagickResourceLimit(MemoryResource,memory_resource);
2688             }
2689           if ((type & FormatsMemoryValidate) != 0)
2690             {
2691               (void) FormatLocaleFile(stdout,"[pixel-cache: memory] ");
2692               tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
2693                 output_filename,&fail,exception);
2694               (void) FormatLocaleFile(stdout,"[pixel-cache: memory] ");
2695               tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
2696                 output_filename,&fail,exception);
2697             }
2698           if ((type & IdentifyValidate) != 0)
2699             tests+=ValidateIdentifyCommand(image_info,reference_filename,
2700               output_filename,&fail,exception);
2701           if ((type & ImportExportValidate) != 0)
2702             tests+=ValidateImportExportPixels(image_info,reference_filename,
2703               output_filename,&fail,exception);
2704           if ((type & MontageValidate) != 0)
2705             tests+=ValidateMontageCommand(image_info,reference_filename,
2706               output_filename,&fail,exception);
2707           if ((type & StreamValidate) != 0)
2708             tests+=ValidateStreamCommand(image_info,reference_filename,
2709               output_filename,&fail,exception);
2710           (void) FormatLocaleFile(stdout,
2711             "validation suite: %.20g tests; %.20g passed; %.20g failed.\n",
2712             (double) tests,(double) (tests-fail),(double) fail);
2713         }
2714       (void) RelinquishUniqueFileResource(output_filename);
2715       (void) RelinquishUniqueFileResource(reference_filename);
2716     }
2717   if (exception->severity != UndefinedException)
2718     CatchException(exception);
2719   if (iterations > 1)
2720     {
2721       elapsed_time=GetElapsedTime(timer);
2722       user_time=GetUserTime(timer);
2723       (void) FormatLocaleFile(stderr,
2724         "Performance: %.20gi %.3fips %0.6fu %ld:%02ld.%03ld\n",(double)
2725         iterations,1.0*iterations/elapsed_time,user_time,(long)
2726         (elapsed_time/60.0),(long) ceil(fmod(elapsed_time,60.0)),
2727         (long) (1000.0*(elapsed_time-floor(elapsed_time))));
2728       timer=DestroyTimerInfo(timer);
2729     }
2730   DestroyValidate();
2731   MagickCoreTerminus();
2732   return(fail == 0 ? 0 : 1);
2733 }
2734