• 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-2020 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.950456
57 #define D65Y  1.0
58 #define D65Z  1.088754
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 *fail,
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 * fail,ExceptionInfo * exception)1023 static size_t ValidateColorspaces(ImageInfo *image_info,size_t *fail,
1024   ExceptionInfo *exception)
1025 {
1026   MagickBooleanType
1027     status;
1028 
1029   size_t
1030     test;
1031 
1032   /*
1033      Reference: https://code.google.com/p/chroma.
1034 
1035      Illuminant =  D65
1036      Observer   =  2° (1931)
1037 
1038      XYZ            0.470645,   0.730177,   0.288323
1039      sRGB           0.545877,   0.966567,   0.463759
1040      CAT02 LMS      0.611749,   0.910088,   0.294880
1041      Y'DbDr         0.783460,  -0.480932,   0.451670
1042      Y'IQ           0.783460,  -0.089078,  -0.245399
1043      Y'PbPr         0.783460,  -0.180419,  -0.169461
1044      Y'UV           0.783460,  -0.157383,  -0.208443
1045      JPEG-Y'CbCr    0.783460,   0.319581,   0.330539
1046      L*u*v*        88.456154, -51.330414,  76.405526
1047      L*a*b*        88.456154, -54.671483,  51.662818
1048      L*C*H*        88.456154,  75.219797, 136.620717
1049      HSV          110.200859,   0.520200,   0.966567
1050      HSL          110.200859,   0.882623,   0.715163
1051      HSI          111.244375,   0.295985,   0.658734
1052      Y'CbCr       187.577791,  87.586330,  90.040886
1053   */
1054   (void) FormatLocaleFile(stdout,"validate colorspaces:\n");
1055   for (test=0; test < 26; test++)
1056   {
1057     CatchException(exception);
1058     (void) FormatLocaleFile(stdout,"  test %.20g: ",(double) test);
1059     switch (test)
1060     {
1061       case  0: status=ValidateHSIToRGB(); break;
1062       case  1: status=ValidateRGBToHSI(); break;
1063       case  2: status=ValidateHSLToRGB(); break;
1064       case  3: status=ValidateRGBToHSL(); break;
1065       case  4: status=ValidateHSVToRGB(); break;
1066       case  5: status=ValidateRGBToHSV(); break;
1067       case  6: status=ValidateJPEGYCbCrToRGB(); break;
1068       case  7: status=ValidateRGBToJPEGYCbCr(); break;
1069       case  8: status=ValidateLabToRGB(); break;
1070       case  9: status=ValidateRGBToLab(); break;
1071       case 10: status=ValidateLchToRGB(); break;
1072       case 11: status=ValidateRGBToLch(); break;
1073       case 12: status=ValidateLMSToRGB(); break;
1074       case 13: status=ValidateRGBToLMS(); break;
1075       case 14: status=ValidateLuvToRGB(); break;
1076       case 15: status=ValidateRGBToLuv(); break;
1077       case 16: status=ValidateXYZToRGB(); break;
1078       case 17: status=ValidateRGBToXYZ(); break;
1079       case 18: status=ValidateYDbDrToRGB(); break;
1080       case 19: status=ValidateRGBToYDbDr(); break;
1081       case 20: status=ValidateYIQToRGB(); break;
1082       case 21: status=ValidateRGBToYIQ(); break;
1083       case 22: status=ValidateYPbPrToRGB(); break;
1084       case 23: status=ValidateRGBToYPbPr(); break;
1085       case 24: status=ValidateYUVToRGB(); break;
1086       case 25: status=ValidateRGBToYUV(); break;
1087       default: status=MagickFalse;
1088     }
1089     if (status == MagickFalse)
1090       {
1091         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1092           GetMagickModule());
1093         (*fail)++;
1094         continue;
1095       }
1096     (void) FormatLocaleFile(stdout,"... pass.\n");
1097   }
1098   (void) FormatLocaleFile(stdout,
1099     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1100     (double) (test-(*fail)),(double) *fail);
1101   return(test);
1102 }
1103 
1104 /*
1105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1106 %                                                                             %
1107 %                                                                             %
1108 %                                                                             %
1109 %   V a l i d a t e C o m p a r e C o m m a n d                               %
1110 %                                                                             %
1111 %                                                                             %
1112 %                                                                             %
1113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1114 %
1115 %  ValidateCompareCommand() validates the ImageMagick compare command line
1116 %  program and returns the number of validation tests that passed and failed.
1117 %
1118 %  The format of the ValidateCompareCommand method is:
1119 %
1120 %      size_t ValidateCompareCommand(ImageInfo *image_info,
1121 %        const char *reference_filename,const char *output_filename,
1122 %        size_t *fail,ExceptionInfo *exception)
1123 %
1124 %  A description of each parameter follows:
1125 %
1126 %    o image_info: the image info.
1127 %
1128 %    o reference_filename: the reference image filename.
1129 %
1130 %    o output_filename: the output image filename.
1131 %
1132 %    o fail: return the number of validation tests that pass.
1133 %
1134 %    o exception: return any errors or warnings in this structure.
1135 %
1136 */
ValidateCompareCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)1137 static size_t ValidateCompareCommand(ImageInfo *image_info,
1138   const char *reference_filename,const char *output_filename,size_t *fail,
1139   ExceptionInfo *exception)
1140 {
1141   char
1142     **arguments,
1143     command[MagickPathExtent];
1144 
1145   int
1146     number_arguments;
1147 
1148   MagickBooleanType
1149     status;
1150 
1151   register ssize_t
1152     i,
1153     j;
1154 
1155   size_t
1156     test;
1157 
1158   test=0;
1159   (void) FormatLocaleFile(stdout,"validate compare command line program:\n");
1160   for (i=0; compare_options[i] != (char *) NULL; i++)
1161   {
1162     CatchException(exception);
1163     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
1164       compare_options[i]);
1165     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s %s",
1166       compare_options[i],reference_filename,reference_filename,output_filename);
1167     arguments=StringToArgv(command,&number_arguments);
1168     if (arguments == (char **) NULL)
1169       {
1170         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1171           GetMagickModule());
1172         (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),"%s",
1173           exception->reason);
1174         (*fail)++;
1175         continue;
1176       }
1177     status=CompareImagesCommand(image_info,number_arguments,arguments,
1178       (char **) NULL,exception);
1179     for (j=0; j < (ssize_t) number_arguments; j++)
1180       arguments[j]=DestroyString(arguments[j]);
1181     arguments=(char **) RelinquishMagickMemory(arguments);
1182     if (status == MagickFalse)
1183       {
1184         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1185           GetMagickModule());
1186         (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),"%s",
1187           exception->reason);
1188         (*fail)++;
1189         continue;
1190       }
1191     (void) FormatLocaleFile(stdout,"... pass.\n");
1192   }
1193   (void) FormatLocaleFile(stdout,
1194     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1195     (double) (test-(*fail)),(double) *fail);
1196   return(test);
1197 }
1198 
1199 /*
1200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1201 %                                                                             %
1202 %                                                                             %
1203 %                                                                             %
1204 %   V a l i d a t e C o m p o s i t e C o m m a n d                           %
1205 %                                                                             %
1206 %                                                                             %
1207 %                                                                             %
1208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209 %
1210 %  ValidateCompositeCommand() validates the ImageMagick composite command line
1211 %  program and returns the number of validation tests that passed and failed.
1212 %
1213 %  The format of the ValidateCompositeCommand method is:
1214 %
1215 %      size_t ValidateCompositeCommand(ImageInfo *image_info,
1216 %        const char *reference_filename,const char *output_filename,
1217 %        size_t *fail,ExceptionInfo *exception)
1218 %
1219 %  A description of each parameter follows:
1220 %
1221 %    o image_info: the image info.
1222 %
1223 %    o reference_filename: the reference image filename.
1224 %
1225 %    o output_filename: the output image filename.
1226 %
1227 %    o fail: return the number of validation tests that pass.
1228 %
1229 %    o exception: return any errors or warnings in this structure.
1230 %
1231 */
ValidateCompositeCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)1232 static size_t ValidateCompositeCommand(ImageInfo *image_info,
1233   const char *reference_filename,const char *output_filename,size_t *fail,
1234   ExceptionInfo *exception)
1235 {
1236   char
1237     **arguments,
1238     command[MagickPathExtent];
1239 
1240   int
1241     number_arguments;
1242 
1243   MagickBooleanType
1244     status;
1245 
1246   register ssize_t
1247     i,
1248     j;
1249 
1250   size_t
1251     test;
1252 
1253   test=0;
1254   (void) FormatLocaleFile(stdout,"validate composite command line program:\n");
1255   for (i=0; composite_options[i] != (char *) NULL; i++)
1256   {
1257     CatchException(exception);
1258     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
1259       composite_options[i]);
1260     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s %s",
1261       reference_filename,composite_options[i],reference_filename,
1262       output_filename);
1263     arguments=StringToArgv(command,&number_arguments);
1264     if (arguments == (char **) NULL)
1265       {
1266         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1267           GetMagickModule());
1268         (*fail)++;
1269         continue;
1270       }
1271     status=CompositeImageCommand(image_info,number_arguments,arguments,
1272       (char **) NULL,exception);
1273     for (j=0; j < (ssize_t) number_arguments; j++)
1274       arguments[j]=DestroyString(arguments[j]);
1275     arguments=(char **) RelinquishMagickMemory(arguments);
1276     if (status == MagickFalse)
1277       {
1278         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1279           GetMagickModule());
1280         (*fail)++;
1281         continue;
1282       }
1283     (void) FormatLocaleFile(stdout,"... pass.\n");
1284   }
1285   (void) FormatLocaleFile(stdout,
1286     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1287     (double) (test-(*fail)),(double) *fail);
1288   return(test);
1289 }
1290 
1291 /*
1292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1293 %                                                                             %
1294 %                                                                             %
1295 %                                                                             %
1296 %   V a l i d a t e C o n v e r t C o m m a n d                               %
1297 %                                                                             %
1298 %                                                                             %
1299 %                                                                             %
1300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301 %
1302 %  ValidateConvertCommand() validates the ImageMagick convert command line
1303 %  program and returns the number of validation tests that passed and failed.
1304 %
1305 %  The format of the ValidateConvertCommand method is:
1306 %
1307 %      size_t ValidateConvertCommand(ImageInfo *image_info,
1308 %        const char *reference_filename,const char *output_filename,
1309 %        size_t *fail,ExceptionInfo *exception)
1310 %
1311 %  A description of each parameter follows:
1312 %
1313 %    o image_info: the image info.
1314 %
1315 %    o reference_filename: the reference image filename.
1316 %
1317 %    o output_filename: the output image filename.
1318 %
1319 %    o fail: return the number of validation tests that pass.
1320 %
1321 %    o exception: return any errors or warnings in this structure.
1322 %
1323 */
ValidateConvertCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)1324 static size_t ValidateConvertCommand(ImageInfo *image_info,
1325   const char *reference_filename,const char *output_filename,size_t *fail,
1326   ExceptionInfo *exception)
1327 {
1328   char
1329     **arguments,
1330     command[MagickPathExtent];
1331 
1332   int
1333     number_arguments;
1334 
1335   MagickBooleanType
1336     status;
1337 
1338   register ssize_t
1339     i,
1340     j;
1341 
1342   size_t
1343     test;
1344 
1345   test=0;
1346   (void) FormatLocaleFile(stdout,"validate convert command line program:\n");
1347   for (i=0; convert_options[i] != (char *) NULL; i++)
1348   {
1349     CatchException(exception);
1350     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) test++,
1351       convert_options[i]);
1352     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s %s",
1353       reference_filename,convert_options[i],reference_filename,output_filename);
1354     arguments=StringToArgv(command,&number_arguments);
1355     if (arguments == (char **) NULL)
1356       {
1357         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1358           GetMagickModule());
1359         (*fail)++;
1360         continue;
1361       }
1362     status=ConvertImageCommand(image_info,number_arguments,arguments,
1363       (char **) NULL,exception);
1364     for (j=0; j < (ssize_t) number_arguments; j++)
1365       arguments[j]=DestroyString(arguments[j]);
1366     arguments=(char **) RelinquishMagickMemory(arguments);
1367     if (status == MagickFalse)
1368       {
1369         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1370           GetMagickModule());
1371         (*fail)++;
1372         continue;
1373       }
1374     (void) FormatLocaleFile(stdout,"... pass.\n");
1375   }
1376   (void) FormatLocaleFile(stdout,
1377     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1378     (double) (test-(*fail)),(double) *fail);
1379   return(test);
1380 }
1381 
1382 /*
1383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1384 %                                                                             %
1385 %                                                                             %
1386 %                                                                             %
1387 %   V a l i d a t e I d e n t i f y C o m m a n d                             %
1388 %                                                                             %
1389 %                                                                             %
1390 %                                                                             %
1391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 %
1393 %  ValidateIdentifyCommand() validates the ImageMagick identify command line
1394 %  program and returns the number of validation tests that passed and failed.
1395 %
1396 %  The format of the ValidateIdentifyCommand method is:
1397 %
1398 %      size_t ValidateIdentifyCommand(ImageInfo *image_info,
1399 %        const char *reference_filename,const char *output_filename,
1400 %        size_t *fail,ExceptionInfo *exception)
1401 %
1402 %  A description of each parameter follows:
1403 %
1404 %    o image_info: the image info.
1405 %
1406 %    o reference_filename: the reference image filename.
1407 %
1408 %    o output_filename: the output image filename.
1409 %
1410 %    o fail: return the number of validation tests that pass.
1411 %
1412 %    o exception: return any errors or warnings in this structure.
1413 %
1414 */
ValidateIdentifyCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)1415 static size_t ValidateIdentifyCommand(ImageInfo *image_info,
1416   const char *reference_filename,const char *output_filename,size_t *fail,
1417   ExceptionInfo *exception)
1418 {
1419   char
1420     **arguments,
1421     command[MagickPathExtent];
1422 
1423   int
1424     number_arguments;
1425 
1426   MagickBooleanType
1427     status;
1428 
1429   register ssize_t
1430     i,
1431     j;
1432 
1433   size_t
1434     test;
1435 
1436   (void) output_filename;
1437   test=0;
1438   (void) FormatLocaleFile(stdout,"validate identify command line program:\n");
1439   for (i=0; identify_options[i] != (char *) NULL; i++)
1440   {
1441     CatchException(exception);
1442     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) test++,
1443       identify_options[i]);
1444     (void) FormatLocaleString(command,MagickPathExtent,"%s %s",
1445       identify_options[i],reference_filename);
1446     arguments=StringToArgv(command,&number_arguments);
1447     if (arguments == (char **) NULL)
1448       {
1449         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1450           GetMagickModule());
1451         (*fail)++;
1452         continue;
1453       }
1454     status=IdentifyImageCommand(image_info,number_arguments,arguments,
1455       (char **) NULL,exception);
1456     for (j=0; j < (ssize_t) number_arguments; j++)
1457       arguments[j]=DestroyString(arguments[j]);
1458     arguments=(char **) RelinquishMagickMemory(arguments);
1459     if (status == MagickFalse)
1460       {
1461         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1462           GetMagickModule());
1463         (*fail)++;
1464         continue;
1465       }
1466     (void) FormatLocaleFile(stdout,"... pass.\n");
1467   }
1468   (void) FormatLocaleFile(stdout,
1469     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1470     (double) (test-(*fail)),(double) *fail);
1471   return(test);
1472 }
1473 
1474 /*
1475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476 %                                                                             %
1477 %                                                                             %
1478 %                                                                             %
1479 %   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                   %
1480 %                                                                             %
1481 %                                                                             %
1482 %                                                                             %
1483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484 %
1485 %  ValidateImageFormatsInMemory() validates the ImageMagick image formats in
1486 %  memory and returns the number of validation tests that passed and failed.
1487 %
1488 %  The format of the ValidateImageFormatsInMemory method is:
1489 %
1490 %      size_t ValidateImageFormatsInMemory(ImageInfo *image_info,
1491 %        const char *reference_filename,const char *output_filename,
1492 %        size_t *fail,ExceptionInfo *exception)
1493 %
1494 %  A description of each parameter follows:
1495 %
1496 %    o image_info: the image info.
1497 %
1498 %    o reference_filename: the reference image filename.
1499 %
1500 %    o output_filename: the output image filename.
1501 %
1502 %    o fail: return the number of validation tests that pass.
1503 %
1504 %    o exception: return any errors or warnings in this structure.
1505 %
1506 */
1507 
1508 /*
1509   Enable this to count remaining $TMPDIR/magick-* files.  Note that the count
1510   includes any files left over from other runs.
1511 */
1512 #undef MagickCountTempFiles
1513 
ValidateImageFormatsInMemory(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)1514 static size_t ValidateImageFormatsInMemory(ImageInfo *image_info,
1515   const char *reference_filename,const char *output_filename,size_t *fail,
1516   ExceptionInfo *exception)
1517 {
1518   char
1519 #ifdef MagickCountTempFiles
1520     path[MagickPathExtent],
1521     SystemCommand[MagickPathExtent],
1522 #endif
1523     size[MagickPathExtent];
1524 
1525   const MagickInfo
1526     *magick_info;
1527 
1528   double
1529     distortion,
1530     fuzz;
1531 
1532   Image
1533     *difference_image,
1534     *ping_image,
1535     *reconstruct_image,
1536     *reference_image;
1537 
1538   MagickBooleanType
1539     status;
1540 
1541   register ssize_t
1542     i,
1543     j;
1544 
1545   size_t
1546     length,
1547     test;
1548 
1549   unsigned char
1550     *blob;
1551 
1552   test=0;
1553   (void) FormatLocaleFile(stdout,"validate image formats in memory:\n");
1554 
1555 #ifdef MagickCountTempFiles
1556   (void)GetPathTemplate(path);
1557   /* Remove file template except for the leading "/path/to/magick-" */
1558   path[strlen(path)-17]='\0';
1559   (void) FormatLocaleFile(stdout," tmp path is '%s*'\n",path);
1560 #endif
1561 
1562   for (i=0; reference_formats[i].magick != (char *) NULL; i++)
1563   {
1564     magick_info=GetMagickInfo(reference_formats[i].magick,exception);
1565     if ((magick_info == (const MagickInfo *) NULL) ||
1566         (magick_info->decoder == (DecodeImageHandler *) NULL) ||
1567         (magick_info->encoder == (EncodeImageHandler *) NULL))
1568       continue;
1569     for (j=0; reference_types[j].type != UndefinedType; j++)
1570     {
1571       /*
1572         Generate reference image.
1573       */
1574       CatchException(exception);
1575       (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
1576         (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
1577         MagickCompressOptions,reference_formats[i].compression),
1578         CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
1579         (double) reference_types[j].depth);
1580       (void) CopyMagickString(image_info->filename,reference_filename,
1581         MagickPathExtent);
1582       reference_image=ReadImage(image_info,exception);
1583       if ((reference_image == (Image *) NULL) ||
1584           (exception->severity >= ErrorException))
1585         {
1586           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1587             GetMagickModule());
1588           if (exception->reason != (char *) NULL)
1589             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1590           CatchException(exception);
1591           (*fail)++;
1592           continue;
1593         }
1594       /*
1595         Write reference image.
1596       */
1597       (void) FormatLocaleString(size,MagickPathExtent,"%.20gx%.20g",
1598         (double) reference_image->columns,(double) reference_image->rows);
1599       (void) CloneString(&image_info->size,size);
1600       image_info->depth=reference_types[j].depth;
1601       (void) FormatLocaleString(reference_image->filename,MagickPathExtent,
1602         "%s:%s",reference_formats[i].magick,output_filename);
1603       status=SetImageType(reference_image,reference_types[j].type,exception);
1604       if (status == MagickFalse || (exception->severity >= ErrorException))
1605         {
1606           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1607             GetMagickModule());
1608           if (exception->reason != (char *) NULL)
1609             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1610           CatchException(exception);
1611           (*fail)++;
1612           reference_image=DestroyImage(reference_image);
1613           continue;
1614         }
1615       status=SetImageDepth(reference_image,reference_types[j].depth,exception);
1616       if (status == MagickFalse || (exception->severity >= ErrorException))
1617         {
1618           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1619             GetMagickModule());
1620           CatchException(exception);
1621           (*fail)++;
1622           reference_image=DestroyImage(reference_image);
1623           continue;
1624         }
1625       reference_image->compression=reference_formats[i].compression;
1626       status=WriteImage(image_info,reference_image,exception);
1627       reference_image=DestroyImage(reference_image);
1628       if (status == MagickFalse || (exception->severity >= ErrorException))
1629         {
1630           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1631             GetMagickModule());
1632           if (exception->reason != (char *) NULL)
1633             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1634           CatchException(exception);
1635           (*fail)++;
1636           continue;
1637         }
1638       /*
1639         Ping reference image.
1640       */
1641       (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s:%s",
1642         reference_formats[i].magick,output_filename);
1643       ping_image=PingImage(image_info,exception);
1644       if (ping_image == (Image *) NULL ||
1645           (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       ping_image=DestroyImage(ping_image);
1656       /*
1657         Read reference image.
1658       */
1659       reference_image=ReadImage(image_info,exception);
1660       if ((reference_image == (Image *) NULL) ||
1661           (exception->severity >= ErrorException))
1662         {
1663           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1664             GetMagickModule());
1665           if (exception->reason != (char *) NULL)
1666             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1667           CatchException(exception);
1668           (*fail)++;
1669           continue;
1670         }
1671       /*
1672         Write reference image.
1673       */
1674       (void) FormatLocaleString(reference_image->filename,MagickPathExtent,
1675         "%s:%s",reference_formats[i].magick,output_filename);
1676       (void) CopyMagickString(image_info->magick,reference_formats[i].magick,
1677         MagickPathExtent);
1678       reference_image->depth=reference_types[j].depth;
1679       reference_image->compression=reference_formats[i].compression;
1680       length=8192;
1681       blob=(unsigned char *) ImageToBlob(image_info,reference_image,&length,
1682         exception);
1683       if ((blob == (unsigned char *) NULL) ||
1684           (exception->severity >= ErrorException))
1685         {
1686           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1687             GetMagickModule());
1688           if (exception->reason != (char *) NULL)
1689             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1690           CatchException(exception);
1691           (*fail)++;
1692           reference_image=DestroyImage(reference_image);
1693           continue;
1694         }
1695       /*
1696         Ping reference blob.
1697       */
1698       ping_image=PingBlob(image_info,blob,length,exception);
1699       if (ping_image == (Image *) NULL ||
1700           (exception->severity >= ErrorException))
1701         {
1702           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1703             GetMagickModule());
1704           if (exception->reason != (char *) NULL)
1705             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1706           CatchException(exception);
1707           (*fail)++;
1708           blob=(unsigned char *) RelinquishMagickMemory(blob);
1709           continue;
1710         }
1711       ping_image=DestroyImage(ping_image);
1712       /*
1713         Read reconstruct image.
1714       */
1715       (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s:%s",
1716         reference_formats[i].magick,output_filename);
1717       reconstruct_image=BlobToImage(image_info,blob,length,exception);
1718       blob=(unsigned char *) RelinquishMagickMemory(blob);
1719       if (reconstruct_image == (Image *) NULL ||
1720           (exception->severity >= ErrorException))
1721         {
1722           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1723             GetMagickModule());
1724           if (exception->reason != (char *) NULL)
1725             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1726           CatchException(exception);
1727           (*fail)++;
1728           reference_image=DestroyImage(reference_image);
1729           continue;
1730         }
1731       /*
1732         Compare reference to reconstruct image.
1733       */
1734       fuzz=0.003;  /* grayscale */
1735       if (reference_formats[i].fuzz != 0.0)
1736         fuzz=reference_formats[i].fuzz;
1737       difference_image=CompareImages(reference_image,reconstruct_image,
1738         RootMeanSquaredErrorMetric,&distortion,exception);
1739       reconstruct_image=DestroyImage(reconstruct_image);
1740       reference_image=DestroyImage(reference_image);
1741       if (difference_image == (Image *) NULL ||
1742           (exception->severity >= ErrorException))
1743         {
1744           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1745             GetMagickModule());
1746           if (exception->reason != (char *) NULL)
1747             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1748           CatchException(exception);
1749           (*fail)++;
1750           continue;
1751         }
1752       difference_image=DestroyImage(difference_image);
1753       if ((QuantumScale*distortion) > fuzz)
1754         {
1755           (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
1756             QuantumScale*distortion);
1757           (*fail)++;
1758           continue;
1759         }
1760 #ifdef MagickCountTempFiles
1761       (void) FormatLocaleFile(stdout,"... pass, ");
1762       (void) fflush(stdout);
1763       SystemCommand[0]='\0';
1764       (void) strncat(SystemCommand,"echo `ls ",9);
1765       (void) strncat(SystemCommand,path,MagickPathExtent-31);
1766       (void) strncat(SystemCommand,"* | wc -w` tmp files.",20);
1767       (void) system(SystemCommand);
1768       (void) fflush(stdout);
1769 #else
1770       (void) FormatLocaleFile(stdout,"... pass\n");
1771 #endif
1772     }
1773   }
1774   (void) FormatLocaleFile(stdout,
1775     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1776     (double) (test-(*fail)),(double) *fail);
1777   return(test);
1778 }
1779 
1780 /*
1781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1782 %                                                                             %
1783 %                                                                             %
1784 %                                                                             %
1785 %   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                       %
1786 %                                                                             %
1787 %                                                                             %
1788 %                                                                             %
1789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790 %
1791 %  ValidateImageFormatsOnDisk() validates the ImageMagick image formats on disk
1792 %  and returns the number of validation tests that passed and failed.
1793 %
1794 %  The format of the ValidateImageFormatsOnDisk method is:
1795 %
1796 %      size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
1797 %        const char *reference_filename,const char *output_filename,
1798 %        size_t *fail,ExceptionInfo *exception)
1799 %
1800 %  A description of each parameter follows:
1801 %
1802 %    o image_info: the image info.
1803 %
1804 %    o reference_filename: the reference image filename.
1805 %
1806 %    o output_filename: the output image filename.
1807 %
1808 %    o fail: return the number of validation tests that pass.
1809 %
1810 %    o exception: return any errors or warnings in this structure.
1811 %
1812 */
ValidateImageFormatsOnDisk(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)1813 static size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
1814   const char *reference_filename,const char *output_filename,size_t *fail,
1815   ExceptionInfo *exception)
1816 {
1817   char
1818     size[MagickPathExtent];
1819 
1820   const MagickInfo
1821     *magick_info;
1822 
1823   double
1824     distortion,
1825     fuzz;
1826 
1827   Image
1828     *difference_image,
1829     *reference_image,
1830     *reconstruct_image;
1831 
1832   MagickBooleanType
1833     status;
1834 
1835   register ssize_t
1836     i,
1837     j;
1838 
1839   size_t
1840     test;
1841 
1842   test=0;
1843   (void) FormatLocaleFile(stdout,"validate image formats on disk:\n");
1844   for (i=0; reference_formats[i].magick != (char *) NULL; i++)
1845   {
1846     magick_info=GetMagickInfo(reference_formats[i].magick,exception);
1847     if ((magick_info == (const MagickInfo *) NULL) ||
1848         (magick_info->decoder == (DecodeImageHandler *) NULL) ||
1849         (magick_info->encoder == (EncodeImageHandler *) NULL))
1850       continue;
1851     for (j=0; reference_types[j].type != UndefinedType; j++)
1852     {
1853       /*
1854         Generate reference image.
1855       */
1856       CatchException(exception);
1857       (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
1858         (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
1859         MagickCompressOptions,reference_formats[i].compression),
1860         CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
1861         (double) reference_types[j].depth);
1862       (void) CopyMagickString(image_info->filename,reference_filename,
1863         MagickPathExtent);
1864       reference_image=ReadImage(image_info,exception);
1865       if ((reference_image == (Image *) NULL) ||
1866           (exception->severity >= ErrorException))
1867         {
1868           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1869             GetMagickModule());
1870           if (exception->reason != (char *) NULL)
1871             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1872           CatchException(exception);
1873           (*fail)++;
1874           continue;
1875         }
1876       /*
1877         Write reference image.
1878       */
1879       (void) FormatLocaleString(size,MagickPathExtent,"%.20gx%.20g",
1880         (double) reference_image->columns,(double) reference_image->rows);
1881       (void) CloneString(&image_info->size,size);
1882       image_info->depth=reference_types[j].depth;
1883       (void) FormatLocaleString(reference_image->filename,MagickPathExtent,
1884         "%s:%s",reference_formats[i].magick,output_filename);
1885       status=SetImageType(reference_image,reference_types[j].type,exception);
1886       if (status == MagickFalse || (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           reference_image=DestroyImage(reference_image);
1895           continue;
1896         }
1897       status=SetImageDepth(reference_image,reference_types[j].depth,exception);
1898       if (status == MagickFalse || (exception->severity >= ErrorException))
1899         {
1900           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1901             GetMagickModule());
1902           CatchException(exception);
1903           (*fail)++;
1904           reference_image=DestroyImage(reference_image);
1905           continue;
1906         }
1907       reference_image->compression=reference_formats[i].compression;
1908       status=WriteImage(image_info,reference_image,exception);
1909       reference_image=DestroyImage(reference_image);
1910       if (status == MagickFalse || (exception->severity >= ErrorException))
1911         {
1912           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1913             GetMagickModule());
1914           if (exception->reason != (char *) NULL)
1915             (void) FormatLocaleFile(stdout,"    reason:%s\n",exception->reason);
1916           CatchException(exception);
1917           (*fail)++;
1918           continue;
1919         }
1920       /*
1921         Read reference image.
1922       */
1923       (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s:%s",
1924         reference_formats[i].magick,output_filename);
1925       reference_image=ReadImage(image_info,exception);
1926       if ((reference_image == (Image *) NULL) ||
1927           (exception->severity >= ErrorException))
1928         {
1929           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1930             GetMagickModule());
1931           CatchException(exception);
1932           (*fail)++;
1933           continue;
1934         }
1935       /*
1936         Write reference image.
1937       */
1938       (void) FormatLocaleString(reference_image->filename,MagickPathExtent,
1939         "%s:%s",reference_formats[i].magick,output_filename);
1940       reference_image->depth=reference_types[j].depth;
1941       reference_image->compression=reference_formats[i].compression;
1942       status=WriteImage(image_info,reference_image,exception);
1943       if (status == MagickFalse ||exception->severity >= ErrorException)
1944         {
1945           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1946             GetMagickModule());
1947           CatchException(exception);
1948           (*fail)++;
1949           reference_image=DestroyImage(reference_image);
1950           continue;
1951         }
1952       /*
1953         Read reconstruct image.
1954       */
1955       (void) FormatLocaleString(image_info->filename,MagickPathExtent,"%s:%s",
1956         reference_formats[i].magick,output_filename);
1957       reconstruct_image=ReadImage(image_info,exception);
1958       if (reconstruct_image == (Image *) NULL ||
1959           (exception->severity >= ErrorException))
1960         {
1961           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1962             GetMagickModule());
1963           CatchException(exception);
1964           (*fail)++;
1965           reference_image=DestroyImage(reference_image);
1966           continue;
1967         }
1968       /*
1969         Compare reference to reconstruct image.
1970       */
1971       fuzz=0.003;  /* grayscale */
1972       if (reference_formats[i].fuzz != 0.0)
1973         fuzz=reference_formats[i].fuzz;
1974       difference_image=CompareImages(reference_image,reconstruct_image,
1975         RootMeanSquaredErrorMetric,&distortion,exception);
1976       reconstruct_image=DestroyImage(reconstruct_image);
1977       reference_image=DestroyImage(reference_image);
1978       if (difference_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           continue;
1986         }
1987       difference_image=DestroyImage(difference_image);
1988       if ((QuantumScale*distortion) > fuzz)
1989         {
1990           (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
1991             QuantumScale*distortion);
1992           (*fail)++;
1993           continue;
1994         }
1995       (void) FormatLocaleFile(stdout,"... pass.\n");
1996     }
1997   }
1998   (void) FormatLocaleFile(stdout,
1999     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
2000     (double) (test-(*fail)),(double) *fail);
2001   return(test);
2002 }
2003 
2004 /*
2005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2006 %                                                                             %
2007 %                                                                             %
2008 %                                                                             %
2009 %   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                       %
2010 %                                                                             %
2011 %                                                                             %
2012 %                                                                             %
2013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2014 %
2015 %  ValidateImportExportPixels() validates the pixel import and export methods.
2016 %  It returns the number of validation tests that passed and failed.
2017 %
2018 %  The format of the ValidateImportExportPixels method is:
2019 %
2020 %      size_t ValidateImportExportPixels(ImageInfo *image_info,
2021 %        const char *reference_filename,const char *output_filename,
2022 %        size_t *fail,ExceptionInfo *exception)
2023 %
2024 %  A description of each parameter follows:
2025 %
2026 %    o image_info: the image info.
2027 %
2028 %    o reference_filename: the reference image filename.
2029 %
2030 %    o output_filename: the output image filename.
2031 %
2032 %    o fail: return the number of validation tests that pass.
2033 %
2034 %    o exception: return any errors or warnings in this structure.
2035 %
2036 */
ValidateImportExportPixels(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)2037 static size_t ValidateImportExportPixels(ImageInfo *image_info,
2038   const char *reference_filename,const char *output_filename,size_t *fail,
2039   ExceptionInfo *exception)
2040 {
2041   double
2042     distortion;
2043 
2044   Image
2045     *difference_image,
2046     *reference_image,
2047     *reconstruct_image;
2048 
2049   MagickBooleanType
2050     status;
2051 
2052   register ssize_t
2053     i,
2054     j;
2055 
2056   size_t
2057     length;
2058 
2059   unsigned char
2060     *pixels;
2061 
2062   size_t
2063     test;
2064 
2065   (void) output_filename;
2066   test=0;
2067   (void) FormatLocaleFile(stdout,
2068     "validate the import and export of image pixels:\n");
2069   for (i=0; reference_map[i] != (char *) NULL; i++)
2070   {
2071     for (j=0; reference_storage[j].type != UndefinedPixel; j++)
2072     {
2073       /*
2074         Generate reference image.
2075       */
2076       CatchException(exception);
2077       (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s",(double) (test++),
2078         reference_map[i],CommandOptionToMnemonic(MagickStorageOptions,
2079         reference_storage[j].type));
2080       (void) CopyMagickString(image_info->filename,reference_filename,
2081         MagickPathExtent);
2082       reference_image=ReadImage(image_info,exception);
2083       if ((reference_image == (Image *) NULL) ||
2084           (exception->severity >= ErrorException))
2085         {
2086           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2087             GetMagickModule());
2088           CatchException(exception);
2089           (*fail)++;
2090           continue;
2091         }
2092       if (LocaleNCompare(reference_map[i],"cmy",3) == 0)
2093         (void) SetImageColorspace(reference_image,CMYKColorspace,exception);
2094       length=strlen(reference_map[i])*reference_image->columns*
2095         reference_image->rows*reference_storage[j].quantum;
2096       pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
2097       if (pixels == (unsigned char *) NULL ||
2098           (exception->severity >= ErrorException))
2099         {
2100           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2101             GetMagickModule());
2102           CatchException(exception);
2103           (*fail)++;
2104           reference_image=DestroyImage(reference_image);
2105           continue;
2106         }
2107       (void) memset(pixels,0,length*sizeof(*pixels));
2108       status=ExportImagePixels(reference_image,0,0,reference_image->columns,
2109         reference_image->rows,reference_map[i],reference_storage[j].type,pixels,
2110         exception);
2111       if (status == MagickFalse || (exception->severity >= ErrorException))
2112         {
2113           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2114             GetMagickModule());
2115           CatchException(exception);
2116           (*fail)++;
2117           pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2118           reference_image=DestroyImage(reference_image);
2119           continue;
2120         }
2121       (void) SetImageBackgroundColor(reference_image,exception);
2122       status=ImportImagePixels(reference_image,0,0,reference_image->columns,
2123         reference_image->rows,reference_map[i],reference_storage[j].type,
2124         pixels,exception);
2125       if (status == MagickFalse || (exception->severity >= ErrorException))
2126         {
2127           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2128             GetMagickModule());
2129           CatchException(exception);
2130           (*fail)++;
2131            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2132           reference_image=DestroyImage(reference_image);
2133           continue;
2134         }
2135       /*
2136         Read reconstruct image.
2137       */
2138       reconstruct_image=AcquireImage(image_info,exception);
2139       (void) SetImageExtent(reconstruct_image,reference_image->columns,
2140         reference_image->rows,exception);
2141       (void) SetImageColorspace(reconstruct_image,reference_image->colorspace,
2142         exception);
2143       (void) SetImageBackgroundColor(reconstruct_image,exception);
2144       status=ImportImagePixels(reconstruct_image,0,0,reconstruct_image->columns,
2145         reconstruct_image->rows,reference_map[i],reference_storage[j].type,
2146         pixels,exception);
2147       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
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           reference_image=DestroyImage(reference_image);
2155           continue;
2156         }
2157       /*
2158         Compare reference to reconstruct image.
2159       */
2160       difference_image=CompareImages(reference_image,reconstruct_image,
2161         RootMeanSquaredErrorMetric,&distortion,exception);
2162       reconstruct_image=DestroyImage(reconstruct_image);
2163       reference_image=DestroyImage(reference_image);
2164       if (difference_image == (Image *) NULL ||
2165           (exception->severity >= ErrorException))
2166         {
2167           (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2168             GetMagickModule());
2169           CatchException(exception);
2170           (*fail)++;
2171           continue;
2172         }
2173       difference_image=DestroyImage(difference_image);
2174       if ((QuantumScale*distortion) > 0.0)
2175         {
2176           (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
2177             QuantumScale*distortion);
2178           (*fail)++;
2179           continue;
2180         }
2181       (void) FormatLocaleFile(stdout,"... pass.\n");
2182     }
2183   }
2184   (void) FormatLocaleFile(stdout,
2185     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
2186     (double) (test-(*fail)),(double) *fail);
2187   return(test);
2188 }
2189 
2190 /*
2191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2192 %                                                                             %
2193 %                                                                             %
2194 %                                                                             %
2195 %   V a l i d a t e M o n t a g e C o m m a n d                               %
2196 %                                                                             %
2197 %                                                                             %
2198 %                                                                             %
2199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2200 %
2201 %  ValidateMontageCommand() validates the ImageMagick montage command line
2202 %  program and returns the number of validation tests that passed and failed.
2203 %
2204 %  The format of the ValidateMontageCommand method is:
2205 %
2206 %      size_t ValidateMontageCommand(ImageInfo *image_info,
2207 %        const char *reference_filename,const char *output_filename,
2208 %        size_t *fail,ExceptionInfo *exception)
2209 %
2210 %  A description of each parameter follows:
2211 %
2212 %    o image_info: the image info.
2213 %
2214 %    o reference_filename: the reference image filename.
2215 %
2216 %    o output_filename: the output image filename.
2217 %
2218 %    o fail: return the number of validation tests that pass.
2219 %
2220 %    o exception: return any errors or warnings in this structure.
2221 %
2222 */
ValidateMontageCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)2223 static size_t ValidateMontageCommand(ImageInfo *image_info,
2224   const char *reference_filename,const char *output_filename,size_t *fail,
2225   ExceptionInfo *exception)
2226 {
2227   char
2228     **arguments,
2229     command[MagickPathExtent];
2230 
2231   int
2232     number_arguments;
2233 
2234   MagickBooleanType
2235     status;
2236 
2237   register ssize_t
2238     i,
2239     j;
2240 
2241   size_t
2242     test;
2243 
2244   test=0;
2245   (void) FormatLocaleFile(stdout,"validate montage command line program:\n");
2246   for (i=0; montage_options[i] != (char *) NULL; i++)
2247   {
2248     CatchException(exception);
2249     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
2250       montage_options[i]);
2251     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s %s",
2252       reference_filename,montage_options[i],reference_filename,
2253       output_filename);
2254     arguments=StringToArgv(command,&number_arguments);
2255     if (arguments == (char **) NULL)
2256       {
2257         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2258             GetMagickModule());
2259         (*fail)++;
2260         continue;
2261       }
2262     status=MontageImageCommand(image_info,number_arguments,arguments,
2263       (char **) NULL,exception);
2264     for (j=0; j < (ssize_t) number_arguments; j++)
2265       arguments[j]=DestroyString(arguments[j]);
2266     arguments=(char **) RelinquishMagickMemory(arguments);
2267     if (status == MagickFalse)
2268       {
2269         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2270             GetMagickModule());
2271         (*fail)++;
2272         continue;
2273       }
2274     (void) FormatLocaleFile(stdout,"... pass.\n");
2275   }
2276   (void) FormatLocaleFile(stdout,
2277     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
2278     (double) (test-(*fail)),(double) *fail);
2279   return(test);
2280 }
2281 
2282 /*
2283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284 %                                                                             %
2285 %                                                                             %
2286 %                                                                             %
2287 %   V a l i d a t e S t r e a m C o m m a n d                                 %
2288 %                                                                             %
2289 %                                                                             %
2290 %                                                                             %
2291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2292 %
2293 %  ValidateStreamCommand() validates the ImageMagick stream command line
2294 %  program and returns the number of validation tests that passed and failed.
2295 %
2296 %  The format of the ValidateStreamCommand method is:
2297 %
2298 %      size_t ValidateStreamCommand(ImageInfo *image_info,
2299 %        const char *reference_filename,const char *output_filename,
2300 %        size_t *fail,ExceptionInfo *exception)
2301 %
2302 %  A description of each parameter follows:
2303 %
2304 %    o image_info: the image info.
2305 %
2306 %    o reference_filename: the reference image filename.
2307 %
2308 %    o output_filename: the output image filename.
2309 %
2310 %    o fail: return the number of validation tests that pass.
2311 %
2312 %    o exception: return any errors or warnings in this structure.
2313 %
2314 */
ValidateStreamCommand(ImageInfo * image_info,const char * reference_filename,const char * output_filename,size_t * fail,ExceptionInfo * exception)2315 static size_t ValidateStreamCommand(ImageInfo *image_info,
2316   const char *reference_filename,const char *output_filename,size_t *fail,
2317   ExceptionInfo *exception)
2318 {
2319   char
2320     **arguments,
2321     command[MagickPathExtent];
2322 
2323   int
2324     number_arguments;
2325 
2326   MagickBooleanType
2327     status;
2328 
2329   register ssize_t
2330     i,
2331     j;
2332 
2333   size_t
2334     test;
2335 
2336   test=0;
2337   (void) FormatLocaleFile(stdout,"validate stream command line program:\n");
2338   for (i=0; stream_options[i] != (char *) NULL; i++)
2339   {
2340     CatchException(exception);
2341     (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
2342       stream_options[i]);
2343     (void) FormatLocaleString(command,MagickPathExtent,"%s %s %s",
2344       stream_options[i],reference_filename,output_filename);
2345     arguments=StringToArgv(command,&number_arguments);
2346     if (arguments == (char **) NULL)
2347       {
2348         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2349             GetMagickModule());
2350         (*fail)++;
2351         continue;
2352       }
2353     status=StreamImageCommand(image_info,number_arguments,arguments,
2354       (char **) NULL,exception);
2355     for (j=0; j < (ssize_t) number_arguments; j++)
2356       arguments[j]=DestroyString(arguments[j]);
2357     arguments=(char **) RelinquishMagickMemory(arguments);
2358     if (status == MagickFalse)
2359       {
2360         (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
2361             GetMagickModule());
2362         (*fail)++;
2363         continue;
2364       }
2365     (void) FormatLocaleFile(stdout,"... pass.\n");
2366   }
2367   (void) FormatLocaleFile(stdout,
2368     "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
2369     (double) (test-(*fail)),(double) *fail);
2370   return(test);
2371 }
2372 
2373 /*
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375 %                                                                             %
2376 %                                                                             %
2377 %                                                                             %
2378 %  M a i n                                                                    %
2379 %                                                                             %
2380 %                                                                             %
2381 %                                                                             %
2382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2383 %
2384 %
2385 */
2386 
ValidateUsage(void)2387 static MagickBooleanType ValidateUsage(void)
2388 {
2389   const char
2390     **p;
2391 
2392   static const char
2393     *miscellaneous[]=
2394     {
2395       "-debug events        display copious debugging information",
2396       "-help                print program options",
2397       "-log format          format of debugging information",
2398       "-validate type       validation type",
2399       "-version             print version information",
2400       (char *) NULL
2401     },
2402     *settings[]=
2403     {
2404       "-regard-warnings     pay attention to warning messages",
2405       "-verbose             print detailed information about the image",
2406       (char *) NULL
2407     };
2408 
2409   (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
2410   (void) printf("Copyright: %s\n\n",GetMagickCopyright());
2411   (void) printf("Features: %s\n",GetMagickFeatures());
2412   (void) printf("Usage: %s [options ...] reference-file\n",GetClientName());
2413   (void) printf("\nValidate Settings:\n");
2414   for (p=settings; *p != (char *) NULL; p++)
2415     (void) printf("  %s\n",*p);
2416   (void) printf("\nMiscellaneous Options:\n");
2417   for (p=miscellaneous; *p != (char *) NULL; p++)
2418     (void) printf("  %s\n",*p);
2419   return(MagickTrue);
2420 }
2421 
main(int argc,char ** argv)2422 int main(int argc,char **argv)
2423 {
2424 #define DestroyValidate() \
2425 { \
2426   image_info=DestroyImageInfo(image_info); \
2427   exception=DestroyExceptionInfo(exception); \
2428 }
2429 #define ThrowValidateException(asperity,tag,option) \
2430 { \
2431   (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag,"`%s'", \
2432     option); \
2433   CatchException(exception); \
2434   DestroyValidate(); \
2435   return(MagickFalse); \
2436 }
2437 
2438   char
2439     output_filename[MagickPathExtent],
2440     reference_filename[MagickPathExtent],
2441     *option;
2442 
2443   double
2444     elapsed_time,
2445     user_time;
2446 
2447   ExceptionInfo
2448     *exception;
2449 
2450   Image
2451     *reference_image;
2452 
2453   ImageInfo
2454     *image_info;
2455 
2456   MagickBooleanType
2457     regard_warnings,
2458     status;
2459 
2460   MagickSizeType
2461     memory_resource,
2462     map_resource;
2463 
2464   register ssize_t
2465     i;
2466 
2467   TimerInfo
2468     *timer;
2469 
2470   size_t
2471     fail,
2472     iterations,
2473     tests;
2474 
2475   ValidateType
2476     type;
2477 
2478   /*
2479     Validate the ImageMagick image processing suite.
2480   */
2481   MagickCoreGenesis(*argv,MagickTrue);
2482   (void) setlocale(LC_ALL,"");
2483   (void) setlocale(LC_NUMERIC,"C");
2484   iterations=1;
2485   status=MagickFalse;
2486   type=AllValidate;
2487   regard_warnings=MagickFalse;
2488   (void) regard_warnings;
2489   exception=AcquireExceptionInfo();
2490   image_info=AcquireImageInfo();
2491   (void) CopyMagickString(image_info->filename,ReferenceFilename,
2492     MagickPathExtent);
2493   for (i=1; i < (ssize_t) argc; i++)
2494   {
2495     option=argv[i];
2496     if (IsCommandOption(option) == MagickFalse)
2497       {
2498         (void) CopyMagickString(image_info->filename,option,MagickPathExtent);
2499         continue;
2500       }
2501     switch (*(option+1))
2502     {
2503       case 'b':
2504       {
2505         if (LocaleCompare("bench",option+1) == 0)
2506           {
2507             iterations=StringToUnsignedLong(argv[++i]);
2508             break;
2509           }
2510         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2511       }
2512       case 'd':
2513       {
2514         if (LocaleCompare("debug",option+1) == 0)
2515           {
2516             (void) SetLogEventMask(argv[++i]);
2517             break;
2518           }
2519         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2520       }
2521       case 'h':
2522       {
2523         if (LocaleCompare("help",option+1) == 0)
2524           {
2525             (void) ValidateUsage();
2526             return(0);
2527           }
2528         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2529       }
2530       case 'l':
2531       {
2532         if (LocaleCompare("log",option+1) == 0)
2533           {
2534             if (*option != '+')
2535               (void) SetLogFormat(argv[i+1]);
2536             break;
2537           }
2538         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2539       }
2540       case 'r':
2541       {
2542         if (LocaleCompare("regard-warnings",option+1) == 0)
2543           {
2544             regard_warnings=MagickTrue;
2545             break;
2546           }
2547         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2548       }
2549       case 'v':
2550       {
2551         if (LocaleCompare("validate",option+1) == 0)
2552           {
2553             ssize_t
2554               validate;
2555 
2556             if (*option == '+')
2557               break;
2558             i++;
2559             if (i >= (ssize_t) argc)
2560               ThrowValidateException(OptionError,"MissingArgument",option);
2561             validate=ParseCommandOption(MagickValidateOptions,MagickFalse,
2562               argv[i]);
2563             if (validate < 0)
2564               ThrowValidateException(OptionError,"UnrecognizedValidateType",
2565                 argv[i]);
2566             type=(ValidateType) validate;
2567             break;
2568           }
2569         if ((LocaleCompare("version",option+1) == 0) ||
2570             (LocaleCompare("-version",option+1) == 0))
2571           {
2572             (void) FormatLocaleFile(stdout,"Version: %s\n",
2573               GetMagickVersion((size_t *) NULL));
2574             (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
2575               GetMagickCopyright());
2576             (void) FormatLocaleFile(stdout,"Features: %s\n\n",
2577               GetMagickFeatures());
2578             return(0);
2579           }
2580         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2581       }
2582       default:
2583         ThrowValidateException(OptionError,"UnrecognizedOption",option)
2584     }
2585   }
2586   timer=(TimerInfo *) NULL;
2587   if (iterations > 1)
2588     timer=AcquireTimerInfo();
2589   reference_image=ReadImage(image_info,exception);
2590   tests=0;
2591   fail=0;
2592   if (reference_image == (Image *) NULL)
2593     fail++;
2594   else
2595     {
2596       if (LocaleCompare(image_info->filename,ReferenceFilename) == 0)
2597         (void) CopyMagickString(reference_image->magick,ReferenceImageFormat,
2598           MagickPathExtent);
2599       (void) AcquireUniqueFilename(reference_filename);
2600       (void) AcquireUniqueFilename(output_filename);
2601       (void) CopyMagickString(reference_image->filename,reference_filename,
2602         MagickPathExtent);
2603       status=WriteImage(image_info,reference_image,exception);
2604       reference_image=DestroyImage(reference_image);
2605       if (status == MagickFalse)
2606         fail++;
2607       else
2608         {
2609           (void) FormatLocaleFile(stdout,"Version: %s\n",
2610             GetMagickVersion((size_t *) NULL));
2611           (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
2612             GetMagickCopyright());
2613           (void) FormatLocaleFile(stdout,
2614             "ImageMagick Validation Suite (%s)\n\n",CommandOptionToMnemonic(
2615             MagickValidateOptions,(ssize_t) type));
2616           if ((type & ColorspaceValidate) != 0)
2617             tests+=ValidateColorspaces(image_info,&fail,exception);
2618           if ((type & CompareValidate) != 0)
2619             tests+=ValidateCompareCommand(image_info,reference_filename,
2620               output_filename,&fail,exception);
2621           if ((type & CompositeValidate) != 0)
2622             tests+=ValidateCompositeCommand(image_info,reference_filename,
2623               output_filename,&fail,exception);
2624           if ((type & ConvertValidate) != 0)
2625             tests+=ValidateConvertCommand(image_info,reference_filename,
2626               output_filename,&fail,exception);
2627           if ((type & FormatsDiskValidate) != 0)
2628             {
2629               memory_resource=SetMagickResourceLimit(MemoryResource,0);
2630               map_resource=SetMagickResourceLimit(MapResource,0);
2631               (void) FormatLocaleFile(stdout,"[pixel-cache: disk] ");
2632               tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
2633                 output_filename,&fail,exception);
2634               (void) FormatLocaleFile(stdout,"[pixel-cache: disk] ");
2635               tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
2636                 output_filename,&fail,exception);
2637               (void) SetMagickResourceLimit(MemoryResource,memory_resource);
2638               (void) SetMagickResourceLimit(MapResource,map_resource);
2639             }
2640           if ((type & FormatsMapValidate) != 0)
2641             {
2642               memory_resource=SetMagickResourceLimit(MemoryResource,0);
2643               (void) FormatLocaleFile(stdout,"[pixel-cache: memory-mapped] ");
2644               tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
2645                 output_filename,&fail,exception);
2646               (void) FormatLocaleFile(stdout,"[pixel-cache: memory-mapped] ");
2647               tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
2648                 output_filename,&fail,exception);
2649               (void) SetMagickResourceLimit(MemoryResource,memory_resource);
2650             }
2651           if ((type & FormatsMemoryValidate) != 0)
2652             {
2653               (void) FormatLocaleFile(stdout,"[pixel-cache: memory] ");
2654               tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
2655                 output_filename,&fail,exception);
2656               (void) FormatLocaleFile(stdout,"[pixel-cache: memory] ");
2657               tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
2658                 output_filename,&fail,exception);
2659             }
2660           if ((type & IdentifyValidate) != 0)
2661             tests+=ValidateIdentifyCommand(image_info,reference_filename,
2662               output_filename,&fail,exception);
2663           if ((type & ImportExportValidate) != 0)
2664             tests+=ValidateImportExportPixels(image_info,reference_filename,
2665               output_filename,&fail,exception);
2666           if ((type & MontageValidate) != 0)
2667             tests+=ValidateMontageCommand(image_info,reference_filename,
2668               output_filename,&fail,exception);
2669           if ((type & StreamValidate) != 0)
2670             tests+=ValidateStreamCommand(image_info,reference_filename,
2671               output_filename,&fail,exception);
2672           (void) FormatLocaleFile(stdout,
2673             "validation suite: %.20g tests; %.20g passed; %.20g failed.\n",
2674             (double) tests,(double) (tests-fail),(double) fail);
2675         }
2676       (void) RelinquishUniqueFileResource(output_filename);
2677       (void) RelinquishUniqueFileResource(reference_filename);
2678     }
2679   if (exception->severity != UndefinedException)
2680     CatchException(exception);
2681   if (iterations > 1)
2682     {
2683       elapsed_time=GetElapsedTime(timer);
2684       user_time=GetUserTime(timer);
2685       (void) FormatLocaleFile(stderr,
2686         "Performance: %.20gi %.3fips %0.6fu %ld:%02ld.%03ld\n",(double)
2687         iterations,1.0*iterations/elapsed_time,user_time,(long)
2688         (elapsed_time/60.0),(long) ceil(fmod(elapsed_time,60.0)),
2689         (long) (1000.0*(elapsed_time-floor(elapsed_time))));
2690       timer=DestroyTimerInfo(timer);
2691     }
2692   DestroyValidate();
2693   MagickCoreTerminus();
2694   return(fail == 0 ? 0 : 1);
2695 }
2696