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