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