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