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