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