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