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