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