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