root/tests/validate.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ConvertRGBToXYZ
  2. ConvertXYZToLab
  3. ConvertRGBToLab
  4. ConvertLabToXYZ
  5. ConvertXYZToRGB
  6. ConvertLabToRGB
  7. ConvertRGBToYPbPr
  8. ConvertRGBToYCbCr
  9. ConvertYPbPrToRGB
  10. ConvertYCbCrToRGB
  11. ConvertLCHabToXYZ
  12. ConvertXYZToLCHab
  13. ConvertLMSToXYZ
  14. ConvertLMSToRGB
  15. ConvertXYZToLMS
  16. ConvertRGBToLMS
  17. PerceptibleReciprocal
  18. ConvertXYZToLuv
  19. ConvertRGBToLuv
  20. ConvertLuvToXYZ
  21. ConvertLuvToRGB
  22. ConvertRGBToYDbDr
  23. ConvertYDbDrToRGB
  24. ConvertRGBToYIQ
  25. ConvertYIQToRGB
  26. ConvertRGBToYUV
  27. ConvertYUVToRGB
  28. ValidateHSIToRGB
  29. ValidateRGBToHSI
  30. ValidateHSLToRGB
  31. ValidateRGBToHSL
  32. ValidateHSVToRGB
  33. ValidateRGBToHSV
  34. ValidateRGBToJPEGYCbCr
  35. ValidateJPEGYCbCrToRGB
  36. ValidateLabToRGB
  37. ValidateRGBToLab
  38. ValidateLchToRGB
  39. ValidateRGBToLch
  40. ValidateRGBToLMS
  41. ValidateLMSToRGB
  42. ValidateRGBToLuv
  43. ValidateLuvToRGB
  44. ValidateRGBToXYZ
  45. ValidateXYZToRGB
  46. ValidateYDbDrToRGB
  47. ValidateRGBToYDbDr
  48. ValidateRGBToYIQ
  49. ValidateYIQToRGB
  50. ValidateRGBToYPbPr
  51. ValidateYPbPrToRGB
  52. ValidateRGBToYUV
  53. ValidateYUVToRGB
  54. ValidateColorspaces
  55. ValidateCompareCommand
  56. ValidateCompositeCommand
  57. ValidateConvertCommand
  58. ValidateIdentifyCommand
  59. ValidateImageFormatsInMemory
  60. ValidateImageFormatsOnDisk
  61. ValidateImportExportPixels
  62. ValidateMontageCommand
  63. ValidateStreamCommand
  64. ValidateUsage
  65. main

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%           V   V   AAA   L      IIIII  DDDD    AAA   TTTTT  EEEEE            %
%           V   V  A   A  L        I    D   D  A   A    T    E                %
%           V   V  AAAAA  L        I    D   D  AAAAA    T    EEE              %
%            V V   A   A  L        I    D   D  A   A    T    E                %
%             V    A   A  LLLLL  IIIII  DDDD   A   A    T    EEEEE            %
%                                                                             %
%                                                                             %
%                        ImageMagick Validation Suite                         %
%                                                                             %
%                             Software Design                                 %
%                               John Cristy                                   %
%                               March 2001                                    %
%                                                                             %
%                                                                             %
%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
%  dedicated to making software imaging solutions freely available.           %
%                                                                             %
%  You may not use this file except in compliance with the License.  You may  %
%  obtain a copy of the License at                                            %
%                                                                             %
%    http://www.imagemagick.org/script/license.php                            %
%                                                                             %
%  Unless required by applicable law or agreed to in writing, software        %
%  distributed under the License is distributed on an "AS IS" BASIS,          %
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
%  see the License for the specific language governing permissions and        %
%  limitations under the License.                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/

/*
  Include declarations.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <locale.h>
#include "wand/MagickWand.h"
#include "magick/colorspace-private.h"
#include "magick/resource_.h"
#include "magick/string-private.h"
#include "validate.h"

/*
  Define declarations.
*/
#define CIEEpsilon  (216.0/24389.0)
#define CIEK  (24389.0/27.0)
#define D65X  0.950456
#define D65Y  1.0
#define D65Z  1.088754
#define ReferenceEpsilon  (QuantumRange*1.0e-2)

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   V a l i d a t e C o l o r s p a c e s                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateColorspaces() validates the ImageMagick colorspaces and returns the
%  number of validation tests that passed and failed.
%
%  The format of the ValidateColorspaces method is:
%
%      size_t ValidateColorspaces(ImageInfo *image_info,size_t *fail,
%        ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/

static inline void ConvertRGBToXYZ(const double red,const double green,
  const double blue,double *X,double *Y,double *Z)
{
  double
    b,
    g,
    r;

  r=QuantumScale*DecodePixelGamma(red);
  g=QuantumScale*DecodePixelGamma(green);
  b=QuantumScale*DecodePixelGamma(blue);
  *X=0.41239558896741421610*r+0.35758343076371481710*g+0.18049264738170157350*b;
  *Y=0.21258623078559555160*r+0.71517030370341084990*g+0.07220049864333622685*b;
  *Z=0.01929721549174694484*r+0.11918386458084853180*g+0.95049712513157976600*b;
}

static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
  double *L,double *a,double *b)
{
  double
    x,
    y,
    z;

  if ((X/D65X) > CIEEpsilon)
    x=pow(X/D65X,1.0/3.0);
  else
    x=(CIEK*X/D65X+16.0)/116.0;
  if ((Y/D65Y) > CIEEpsilon)
    y=pow(Y/D65Y,1.0/3.0);
  else
    y=(CIEK*Y/D65Y+16.0)/116.0;
  if ((Z/D65Z) > CIEEpsilon)
    z=pow(Z/D65Z,1.0/3.0);
  else
    z=(CIEK*Z/D65Z+16.0)/116.0;
  *L=((116.0*y)-16.0)/100.0;
  *a=(500.0*(x-y))/255.0+0.5;
  *b=(200.0*(y-z))/255.0+0.5;
}

static void ConvertRGBToLab(const double red,const double green,
  const double blue,double *L,double *a,double *b)
{
  double
    X,
    Y,
    Z;

  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
  ConvertXYZToLab(X,Y,Z,L,a,b);
}

static inline void ConvertLabToXYZ(const double L,const double a,const double b,
  double *X,double *Y,double *Z)
{
  double
    x,
    y,
    z;

  y=(L+16.0)/116.0;
  x=y+a/500.0;
  z=y-b/200.0;
  if ((x*x*x) > CIEEpsilon)
    x=(x*x*x);
  else
    x=(116.0*x-16.0)/CIEK;
  if ((y*y*y) > CIEEpsilon)
    y=(y*y*y);
  else
    y=L/CIEK;
  if ((z*z*z) > CIEEpsilon)
    z=(z*z*z);
  else
    z=(116.0*z-16.0)/CIEK;
  *X=D65X*x;
  *Y=D65Y*y;
  *Z=D65Z*z;
}

static inline void ConvertXYZToRGB(const double x,const double y,const double z,
  Quantum *red,Quantum *green,Quantum *blue)
{
  double
    b,
    g,
    r;

  r=3.2406*x-1.5372*y-0.4986*z;
  g=(-0.9689*x+1.8758*y+0.0415*z);
  b=0.0557*x-0.2040*y+1.0570*z;
  *red=ClampToQuantum(EncodePixelGamma(QuantumRange*r));
  *green=ClampToQuantum(EncodePixelGamma(QuantumRange*g));
  *blue=ClampToQuantum(EncodePixelGamma(QuantumRange*b));
}

static inline void ConvertLabToRGB(const double L,const double a,
  const double b,Quantum *red,Quantum *green,Quantum *blue)
{
  double
    X,
    Y,
    Z;

  ConvertLabToXYZ(L*100.0,255.0*(a-0.5),255.0*(b-0.5),&X,&Y,&Z);
  ConvertXYZToRGB(X,Y,Z,red,green,blue);
}

static void ConvertRGBToYPbPr(const double red,const double green,
  const double blue,double *Y,double *Pb,double *Pr)
{
  *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
  *Pb=QuantumScale*((-0.1687367)*red-0.331264*green+0.5*blue)+0.5;
  *Pr=QuantumScale*(0.5*red-0.418688*green-0.081312*blue)+0.5;
}

static void ConvertRGBToYCbCr(const double red,const double green,
  const double blue,double *Y,double *Cb,double *Cr)
{
  ConvertRGBToYPbPr(red,green,blue,Y,Cb,Cr);
}

static void ConvertYPbPrToRGB(const double Y,const double Pb,const double Pr,
  Quantum *red,Quantum *green,Quantum *blue)
{
  *red=ClampToQuantum(QuantumRange*(0.99999999999914679361*Y-
    1.2188941887145875e-06*(Pb-0.5)+1.4019995886561440468*(Pr-0.5)));
  *green=ClampToQuantum(QuantumRange*(0.99999975910502514331*Y-
    0.34413567816504303521*(Pb-0.5)-0.71413649331646789076*(Pr-0.5)));
  *blue=ClampToQuantum(QuantumRange*(1.00000124040004623180*Y+
    1.77200006607230409200*(Pb-0.5)+2.1453384174593273e-06*(Pr-0.5)));
}

static void ConvertYCbCrToRGB(const double Y,const double Cb,
  const double Cr,Quantum *red,Quantum *green,Quantum *blue)
{
  ConvertYPbPrToRGB(Y,Cb,Cr,red,green,blue);
}

static inline void ConvertLCHabToXYZ(const double luma,const double chroma,
  const double hue,double *X,double *Y,double *Z)
{
  ConvertLabToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
    sin(hue*MagickPI/180.0),X,Y,Z);
}

static inline void ConvertXYZToLCHab(const double X,const double Y,
  const double Z,double *luma,double *chroma,double *hue)
{
  double
    a,
    b;

  ConvertXYZToLab(X,Y,Z,luma,&a,&b);
  *chroma=hypot(255.0*(a-0.5),255.0*(b-0.5))/255.0+0.5;
  *hue=180.0*atan2(255.0*(b-0.5),255.0*(a-0.5))/MagickPI/360.0;
  if (*hue < 0.0)
    *hue+=1.0;
}

static inline void ConvertLMSToXYZ(const double L,const double M,const double S,
  double *X,double *Y,double *Z)
{
  *X=1.096123820835514*L-0.278869000218287*M+0.182745179382773*S;
  *Y=0.454369041975359*L+0.473533154307412*M+0.072097803717229*S;
  *Z=(-0.009627608738429)*L-0.005698031216113*M+1.015325639954543*S;
}

static inline void ConvertLMSToRGB(const double L,const double M,
  const double S,Quantum *red,Quantum *green,Quantum *blue)
{
  double
    X,
    Y,
    Z;

  ConvertLMSToXYZ(L,M,S,&X,&Y,&Z);
  ConvertXYZToRGB(X,Y,Z,red,green,blue);
}

static inline void ConvertXYZToLMS(const double x,const double y,
  const double z,double *L,double *M,double *S)
{
  *L=0.7328*x+0.4296*y-0.1624*z;
  *M=(-0.7036*x+1.6975*y+0.0061*z);
  *S=0.0030*x+0.0136*y+0.9834*z;
}

static void ConvertRGBToLMS(const double red,const double green,
  const double blue,double *L,double *M,double *S)
{
  double
    X,
    Y,
    Z;

  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
  ConvertXYZToLMS(X,Y,Z,L,M,S);
}

static inline double PerceptibleReciprocal(const double x)
{
  double
    sign;

  /*
    Return 1/x where x is perceptible (not unlimited or infinitesimal).
  */
  sign=x < 0.0 ? -1.0 : 1.0;
  if ((sign*x) >= MagickEpsilon)
    return(1.0/x);
  return(sign/MagickEpsilon);
}

static inline void ConvertXYZToLuv(const double X,const double Y,const double Z,
  double *L,double *u,double *v)
{
  double
    alpha;

  if ((Y/D65Y) > CIEEpsilon)
    *L=(double) (116.0*pow(Y/D65Y,1.0/3.0)-16.0);
  else
    *L=CIEK*(Y/D65Y);
  alpha=PerceptibleReciprocal(X+15.0*Y+3.0*Z);
  *u=13.0*(*L)*((4.0*alpha*X)-(4.0*D65X/(D65X+15.0*D65Y+3.0*D65Z)));
  *v=13.0*(*L)*((9.0*alpha*Y)-(9.0*D65Y/(D65X+15.0*D65Y+3.0*D65Z)));
  *L/=100.0;
  *u=(*u+134.0)/354.0;
  *v=(*v+140.0)/262.0;
}

static void ConvertRGBToLuv(const double red,const double green,
  const double blue,double *L,double *u,double *v)
{
  double
    X,
    Y,
    Z;

  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
  ConvertXYZToLuv(X,Y,Z,L,u,v);
}

static inline void ConvertLuvToXYZ(const double L,const double u,const double v,
  double *X,double *Y,double *Z)
{
  if (L > (CIEK*CIEEpsilon))
    *Y=(double) pow((L+16.0)/116.0,3.0);
  else
    *Y=L/CIEK;
  *X=((*Y*((39.0*L/(v+13.0*L*(9.0*D65Y/(D65X+15.0*D65Y+3.0*D65Z))))-5.0))+
    5.0*(*Y))/((((52.0f*L/(u+13.0*L*(4.0*D65X/(D65X+15.0*D65Y+3.0*D65Z))))-1.0)/
    3.0)-(-1.0/3.0));
  *Z=(*X*(((52.0f*L/(u+13.0*L*(4.0*D65X/(D65X+15.0*D65Y+3.0*D65Z))))-1.0)/3.0))-
    5.0*(*Y);
}

static inline void ConvertLuvToRGB(const double L,const double u,
  const double v,Quantum *red,Quantum *green,Quantum *blue)
{
  double
    X,
    Y,
    Z;

  ConvertLuvToXYZ(100.0*L,354.0*u-134.0,262.0*v-140.0,&X,&Y,&Z);
  ConvertXYZToRGB(X,Y,Z,red,green,blue);
}

static void ConvertRGBToYDbDr(const double red,const double green,
  const double blue,double *Y,double *Db,double *Dr)
{
  *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
  *Db=QuantumScale*(-0.450*red-0.883*green+1.333*blue)+0.5;
  *Dr=QuantumScale*(-1.333*red+1.116*green+0.217*blue)+0.5;
}

static void ConvertYDbDrToRGB(const double Y,const double Db,const double Dr,
  Quantum *red,Quantum *green,Quantum *blue)
{
  *red=ClampToQuantum(QuantumRange*(Y+9.2303716147657e-05*(Db-0.5)-
    0.52591263066186533*(Dr-0.5)));
  *green=ClampToQuantum(QuantumRange*(Y-0.12913289889050927*(Db-0.5)+
    0.26789932820759876*(Dr-0.5)));
  *blue=ClampToQuantum(QuantumRange*(Y+0.66467905997895482*(Db-0.5)-
    7.9202543533108e-05*(Dr-0.5)));
}

static void ConvertRGBToYIQ(const double red,const double green,
  const double blue,double *Y,double *I,double *Q)
{
  *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
  *I=QuantumScale*(0.595716*red-0.274453*green-0.321263*blue)+0.5;
  *Q=QuantumScale*(0.211456*red-0.522591*green+0.311135*blue)+0.5;
}

static void ConvertYIQToRGB(const double Y,const double I,const double Q,
  Quantum *red,Quantum *green,Quantum *blue)
{
  *red=ClampToQuantum(QuantumRange*(Y+0.9562957197589482261*(I-0.5)+
    0.6210244164652610754*(Q-0.5)));
  *green=ClampToQuantum(QuantumRange*(Y-0.2721220993185104464*(I-0.5)-
    0.6473805968256950427*(Q-0.5)));
  *blue=ClampToQuantum(QuantumRange*(Y-1.1069890167364901945*(I-0.5)+
    1.7046149983646481374*(Q-0.5)));
}

static void ConvertRGBToYUV(const double red,const double green,
  const double blue,double *Y,double *U,double *V)
{
  *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
  *U=QuantumScale*((-0.147)*red-0.289*green+0.436*blue)+0.5;
  *V=QuantumScale*(0.615*red-0.515*green-0.100*blue)+0.5;
}

static void ConvertYUVToRGB(const double Y,const double U,const double V,
  Quantum *red,Quantum *green,Quantum *blue)
{
  *red=ClampToQuantum(QuantumRange*(Y-3.945707070708279e-05*(U-0.5)+
    1.1398279671717170825*(V-0.5)));
  *green=ClampToQuantum(QuantumRange*(Y-0.3946101641414141437*(U-0.5)-
    0.5805003156565656797*(V-0.5)));
  *blue=ClampToQuantum(QuantumRange*(Y+2.0319996843434342537*(U-0.5)-
    4.813762626262513e-04*(V-0.5)));
}

static MagickBooleanType ValidateHSIToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  HSIToRGB");
  ConvertHSIToRGB(111.244375/360.0,0.295985,0.658734,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToHSI()
{
  double
    h,
    i,
    s;

  (void) FormatLocaleFile(stdout,"  RGBToHSI");
  ConvertRGBToHSI(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&h,&s,&i);
  if ((fabs(h-111.244374/360.0) >= ReferenceEpsilon) ||
      (fabs(s-0.295985) >= ReferenceEpsilon) ||
      (fabs(i-0.658734) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateHSLToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  HSLToRGB");
  ConvertHSLToRGB(110.200859/360.0,0.882623,0.715163,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToHSL()
{
  double
    h,
    l,
    s;

  (void) FormatLocaleFile(stdout,"  RGBToHSL");
  ConvertRGBToHSL(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&h,&s,&l);
  if ((fabs(h-110.200859/360.0) >= ReferenceEpsilon) ||
      (fabs(s-0.882623) >= ReferenceEpsilon) ||
      (fabs(l-0.715163) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateHSVToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  HSVToRGB");
  ConvertHSVToRGB(110.200859/360.0,0.520200,0.966567,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToHSV()
{
  double
    h,
    s,
    v;

  (void) FormatLocaleFile(stdout,"  RGBToHSV");
  ConvertRGBToHSV(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&h,&s,&v);
  if ((fabs(h-110.200859/360.0) >= ReferenceEpsilon) ||
      (fabs(s-0.520200) >= ReferenceEpsilon) ||
      (fabs(v-0.966567) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToJPEGYCbCr()
{
  double
    Cb,
    Cr,
    Y;

  (void) FormatLocaleFile(stdout,"  RGBToJPEGYCbCr");
  ConvertRGBToYCbCr(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&Y,&Cb,&Cr);
  if ((fabs(Y-0.783460) >= ReferenceEpsilon) ||
      (fabs(Cb-0.319581) >= ReferenceEpsilon) ||
      (fabs(Cr-0.330539) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateJPEGYCbCrToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  JPEGYCbCrToRGB");
  ConvertYCbCrToRGB(0.783460,0.319581,0.330539,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateLabToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  LabToRGB");
  ConvertLabToRGB(88.456154/100.0,-54.671483/255+0.5,51.662818/255.0+0.5,
    &r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToLab()
{
  double
    a,
    b,
    L;

  (void) FormatLocaleFile(stdout,"  RGBToLab");
  ConvertRGBToLab(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&L,&a,&b);
  if ((fabs(L-(88.456154/100.0)) >= ReferenceEpsilon) ||
      (fabs(a-(-54.671483/255.0+0.5)) >= ReferenceEpsilon) ||
      (fabs(b-(51.662818/255.0+0.5)) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateLchToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  LchToRGB");
  ConvertLCHabToRGB(88.456154/100.0,75.219797/255.0+0.5,136.620717/360.0,
    &r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToLch()
{
  double
    c,
    h,
    L;

  (void) FormatLocaleFile(stdout,"  RGBToLch");
  ConvertRGBToLCHab(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&L,&c,&h);
  if ((fabs(L-88.456154/100.0) >= ReferenceEpsilon) ||
      (fabs(c-(75.219797/255.0+0.5)) >= ReferenceEpsilon) ||
      (fabs(h-(136.620717/255.0+0.5)) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToLMS()
{
  double
    L,
    M,
    S;

  (void) FormatLocaleFile(stdout,"  RGBToLMS");
  ConvertRGBToLMS(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&L,&M,&S);
  if ((fabs(L-0.611749) >= ReferenceEpsilon) ||
      (fabs(M-0.910088) >= ReferenceEpsilon) ||
      (fabs(S-0.294880) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateLMSToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  LMSToRGB");
  ConvertLMSToRGB(0.611749,0.910088,0.294880,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToLuv()
{
  double
    L,
    u,
    v;

  (void) FormatLocaleFile(stdout,"  RGBToLuv");
  ConvertRGBToLuv(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&L,&u,&v);
  if ((fabs(L-88.456154/262.0) >= ReferenceEpsilon) ||
      (fabs(u-(-51.330414+134.0)/354.0) >= ReferenceEpsilon) ||
      (fabs(v-(76.405526+140.0)/262.0) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateLuvToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  LuvToRGB");
  ConvertLuvToRGB(88.456154/100.0,(-51.330414+134.0)/354.0,
    (76.405526+140.0)/262.0,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToXYZ()
{
  double
    x,
    y,
    z;

  (void) FormatLocaleFile(stdout,"  RGBToXYZ");
  ConvertRGBToXYZ(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&x,&y,&z);
  if ((fabs(x-0.470646) >= ReferenceEpsilon) ||
      (fabs(y-0.730178) >= ReferenceEpsilon) ||
      (fabs(z-0.288324) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateXYZToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  XYZToRGB");
  ConvertXYZToRGB(0.470646,0.730178,0.288324,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateYDbDrToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  YDbDrToRGB");
  ConvertYDbDrToRGB(0.783460,-0.480932+0.5,0.451670+0.5,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToYDbDr()
{
  double
    Db,
    Dr,
    Y;

  (void) FormatLocaleFile(stdout,"  RGBToYDbDr");
  ConvertRGBToYDbDr(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&Y,&Db,&Dr);
  if ((fabs(Y-0.783460) >= ReferenceEpsilon) ||
      (fabs(Db-(-0.480932)) >= ReferenceEpsilon) ||
      (fabs(Dr-0.451670) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToYIQ()
{
  double
    i,
    q,
    y;

  (void) FormatLocaleFile(stdout,"  RGBToYIQ");
  ConvertRGBToYIQ(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&y,&i,&q);
  if ((fabs(y-0.783460) >= ReferenceEpsilon) ||
      (fabs(i-(-0.089078)) >= ReferenceEpsilon) ||
      (fabs(q-(-0.245399)) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateYIQToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  YIQToRGB");
  ConvertYIQToRGB(0.783460,-0.089078+0.5,-0.245399+0.5,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToYPbPr()
{
  double
    Pb,
    Pr,
    Y;

  (void) FormatLocaleFile(stdout,"  RGBToYPbPr");
  ConvertRGBToYPbPr(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&Y,&Pb,&Pr);
  if ((fabs(Y-0.783460) >= ReferenceEpsilon) ||
      (fabs(Pb-(-0.180419)) >= ReferenceEpsilon) ||
      (fabs(Pr-(-0.169461)) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateYPbPrToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  YPbPrToRGB");
  ConvertYPbPrToRGB(0.783460,-0.180419+0.5,-0.169461+0.5,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateRGBToYUV()
{
  double
    U,
    V,
    Y;

  (void) FormatLocaleFile(stdout,"  RGBToYUV");
  ConvertRGBToYUV(0.545877*QuantumRange,0.966567*QuantumRange,
    0.463759*QuantumRange,&Y,&U,&V);
  if ((fabs(Y-0.783460) >= ReferenceEpsilon) ||
      (fabs(U-(-0.157383)) >= ReferenceEpsilon) ||
      (fabs(V-(-0.208443)) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static MagickBooleanType ValidateYUVToRGB()
{
  Quantum
    b,
    g,
    r;

  (void) FormatLocaleFile(stdout,"  YUVToRGB");
  ConvertYUVToRGB(0.783460,-0.157383+0.5,-0.208443+0.5,&r,&g,&b);
  if ((fabs(r-0.545877*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(g-0.966567*QuantumRange) >= ReferenceEpsilon) ||
      (fabs(b-0.463759*QuantumRange) >= ReferenceEpsilon))
    return(MagickFalse);
  return(MagickTrue);
}

static size_t ValidateColorspaces(ImageInfo *image_info,size_t *fail,
  ExceptionInfo *exception)
{
  MagickBooleanType
    status;

  size_t
    test;

  /*
     Reference: https://code.google.com/p/chroma.

     Illuminant =  D65
     Observer   =  2° (1931)

     XYZ            0.470645,   0.730177,   0.288323
     sRGB           0.545877,   0.966567,   0.463759
     CAT02 LMS      0.611749,   0.910088,   0.294880
     Y'DbDr         0.783460,  -0.480932,   0.451670
     Y'IQ           0.783460,  -0.089078,  -0.245399
     Y'PbPr         0.783460,  -0.180419,  -0.169461
     Y'UV           0.783460,  -0.157383,  -0.208443
     JPEG-Y'CbCr    0.783460,   0.319581,   0.330539
     L*u*v*        88.456154, -51.330414,  76.405526
     L*a*b*        88.456154, -54.671483,  51.662818
     L*C*H*        88.456154,  75.219797, 136.620717
     HSV          110.200859,   0.520200,   0.966567
     HSL          110.200859,   0.882623,   0.715163
     HSI          111.244375,   0.295985,   0.658734
     Y'CbCr       187.577791,  87.586330,  90.040886
  */
  (void) FormatLocaleFile(stdout,"validate colorspaces:\n");
  for (test=0; test < 26; test++)
  {
    CatchException(exception);
    (void) FormatLocaleFile(stdout,"  test %.20g: ",(double) test);
    switch (test)
    {
      case  0: status=ValidateHSIToRGB(); break;
      case  1: status=ValidateRGBToHSI(); break;
      case  2: status=ValidateHSLToRGB(); break;
      case  3: status=ValidateRGBToHSL(); break;
      case  4: status=ValidateHSVToRGB(); break;
      case  5: status=ValidateRGBToHSV(); break;
      case  6: status=ValidateJPEGYCbCrToRGB(); break;
      case  7: status=ValidateRGBToJPEGYCbCr(); break;
      case  8: status=ValidateLabToRGB(); break;
      case  9: status=ValidateRGBToLab(); break;
      case 10: status=ValidateLchToRGB(); break;
      case 11: status=ValidateRGBToLch(); break;
      case 12: status=ValidateLMSToRGB(); break;
      case 13: status=ValidateRGBToLMS(); break;
      case 14: status=ValidateLuvToRGB(); break;
      case 15: status=ValidateRGBToLuv(); break;
      case 16: status=ValidateXYZToRGB(); break;
      case 17: status=ValidateRGBToXYZ(); break;
      case 18: status=ValidateYDbDrToRGB(); break;
      case 19: status=ValidateRGBToYDbDr(); break;
      case 20: status=ValidateYIQToRGB(); break;
      case 21: status=ValidateRGBToYIQ(); break;
      case 22: status=ValidateYPbPrToRGB(); break;
      case 23: status=ValidateRGBToYPbPr(); break;
      case 24: status=ValidateYUVToRGB(); break;
      case 25: status=ValidateRGBToYUV(); break;
      default: status=MagickFalse;
    }
    if (status == MagickFalse)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    (void) FormatLocaleFile(stdout,"... pass.\n");
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   V a l i d a t e C o m p a r e C o m m a n d                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateCompareCommand() validates the ImageMagick compare command line
%  program and returns the number of validation tests that passed and failed.
%
%  The format of the ValidateCompareCommand method is:
%
%      size_t ValidateCompareCommand(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static size_t ValidateCompareCommand(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  char
    **arguments,
    command[MaxTextExtent];

  int
    number_arguments;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    test;

  test=0;
  (void) FormatLocaleFile(stdout,"validate compare command line program:\n");
  for (i=0; compare_options[i] != (char *) NULL; i++)
  {
    CatchException(exception);
    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
      compare_options[i]);
    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
      compare_options[i],reference_filename,reference_filename,output_filename);
    arguments=StringToArgv(command,&number_arguments);
    if (arguments == (char **) NULL)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    status=CompareImageCommand(image_info,number_arguments,arguments,
      (char **) NULL,exception);
    for (j=0; j < (ssize_t) number_arguments; j++)
      arguments[j]=DestroyString(arguments[j]);
    arguments=(char **) RelinquishMagickMemory(arguments);
    if (status != MagickFalse)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    (void) FormatLocaleFile(stdout,"... pass.\n");
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   V a l i d a t e C o m p o s i t e C o m m a n d                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateCompositeCommand() validates the ImageMagick composite command line
%  program and returns the number of validation tests that passed and failed.
%
%  The format of the ValidateCompositeCommand method is:
%
%      size_t ValidateCompositeCommand(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static size_t ValidateCompositeCommand(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  char
    **arguments,
    command[MaxTextExtent];

  int
    number_arguments;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    test;

  test=0;
  (void) FormatLocaleFile(stdout,"validate composite command line program:\n");
  for (i=0; composite_options[i] != (char *) NULL; i++)
  {
    CatchException(exception);
    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
      composite_options[i]);
    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
      reference_filename,composite_options[i],reference_filename,
      output_filename);
    arguments=StringToArgv(command,&number_arguments);
    if (arguments == (char **) NULL)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    status=CompositeImageCommand(image_info,number_arguments,arguments,
      (char **) NULL,exception);
    for (j=0; j < (ssize_t) number_arguments; j++)
      arguments[j]=DestroyString(arguments[j]);
    arguments=(char **) RelinquishMagickMemory(arguments);
    if (status != MagickFalse)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    (void) FormatLocaleFile(stdout,"... pass.\n");
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   V a l i d a t e C o n v e r t C o m m a n d                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateConvertCommand() validates the ImageMagick convert command line
%  program and returns the number of validation tests that passed and failed.
%
%  The format of the ValidateConvertCommand method is:
%
%      size_t ValidateConvertCommand(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static size_t ValidateConvertCommand(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  char
    **arguments,
    command[MaxTextExtent];

  int
    number_arguments;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    test;

  test=0;
  (void) FormatLocaleFile(stdout,"validate convert command line program:\n");
  for (i=0; convert_options[i] != (char *) NULL; i++)
  {
    CatchException(exception);
    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) test++,
      convert_options[i]);
    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
      reference_filename,convert_options[i],reference_filename,output_filename);
    arguments=StringToArgv(command,&number_arguments);
    if (arguments == (char **) NULL)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    status=ConvertImageCommand(image_info,number_arguments,arguments,
      (char **) NULL,exception);
    for (j=0; j < (ssize_t) number_arguments; j++)
      arguments[j]=DestroyString(arguments[j]);
    arguments=(char **) RelinquishMagickMemory(arguments);
    if (status != MagickFalse)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    (void) FormatLocaleFile(stdout,"... pass.\n");
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   V a l i d a t e I d e n t i f y C o m m a n d                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateIdentifyCommand() validates the ImageMagick identify command line
%  program and returns the number of validation tests that passed and failed.
%
%  The format of the ValidateIdentifyCommand method is:
%
%      size_t ValidateIdentifyCommand(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static size_t ValidateIdentifyCommand(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  char
    **arguments,
    command[MaxTextExtent];

  int
    number_arguments;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    test;

  (void) output_filename;
  test=0;
  (void) FormatLocaleFile(stdout,"validate identify command line program:\n");
  for (i=0; identify_options[i] != (char *) NULL; i++)
  {
    CatchException(exception);
    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) test++,
      identify_options[i]);
    (void) FormatLocaleString(command,MaxTextExtent,"%s %s",
      identify_options[i],reference_filename);
    arguments=StringToArgv(command,&number_arguments);
    if (arguments == (char **) NULL)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    status=IdentifyImageCommand(image_info,number_arguments,arguments,
      (char **) NULL,exception);
    for (j=0; j < (ssize_t) number_arguments; j++)
      arguments[j]=DestroyString(arguments[j]);
    arguments=(char **) RelinquishMagickMemory(arguments);
    if (status != MagickFalse)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
          GetMagickModule());
        (*fail)++;
        continue;
      }
    (void) FormatLocaleFile(stdout,"... pass.\n");
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateImageFormatsInMemory() validates the ImageMagick image formats in
%  memory and returns the number of validation tests that passed and failed.
%
%  The format of the ValidateImageFormatsInMemory method is:
%
%      size_t ValidateImageFormatsInMemory(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/

/*
  Enable this to count remaining $TMPDIR/magick-* files.  Note that the count
  includes any files left over from other runs.
*/
#undef MagickCountTempFiles

static size_t ValidateImageFormatsInMemory(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  char
#ifdef MagickCountTempFiles
    path[MaxTextExtent],
    SystemCommand[MaxTextExtent],
#endif
    size[MaxTextExtent];

  const MagickInfo
    *magick_info;

  double
    distortion,
    fuzz;

  Image
    *difference_image,
    *ping_image,
    *reference_image,
    *reconstruct_image;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    length;

  unsigned char
    *blob;

  size_t
    test;

  test=0;
  (void) FormatLocaleFile(stdout,"validate image formats in memory:\n");

#ifdef MagickCountTempFiles
  (void) GetPathTemplate(path);
  /* Remove file template except for the leading "/path/to/magick-" */
  path[strlen(path)-17]='\0';
  (void) FormatLocaleFile(stdout," tmp path is '%s*'\n",path);
#endif

  for (i=0; reference_formats[i].magick != (char *) NULL; i++)
  {
    magick_info=GetMagickInfo(reference_formats[i].magick,exception);
    if ((magick_info == (const MagickInfo *) NULL) ||
        (magick_info->decoder == (DecodeImageHandler *) NULL) ||
        (magick_info->encoder == (EncodeImageHandler *) NULL))
      continue;
    for (j=0; reference_types[j].type != UndefinedType; j++)
    {
      /*
        Generate reference image.
      */
      CatchException(exception);
      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
        (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
        MagickCompressOptions,reference_formats[i].compression),
        CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
        (double) reference_types[j].depth);
      (void) CopyMagickString(image_info->filename,reference_filename,
        MaxTextExtent);
      reference_image=ReadImage(image_info,exception);
      if (reference_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      /*
        Write reference image.
      */
      (void) FormatLocaleString(size,MaxTextExtent,"%.20gx%.20g",
        (double) reference_image->columns,(double) reference_image->rows);
      (void) CloneString(&image_info->size,size);
      image_info->depth=reference_types[j].depth;
      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      status=SetImageType(reference_image,reference_types[j].type);
      InheritException(exception,&reference_image->exception);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      status=SetImageDepth(reference_image,reference_types[j].depth);
      InheritException(exception,&reference_image->exception);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      reference_image->compression=reference_formats[i].compression;
      status=WriteImage(image_info,reference_image);
      InheritException(exception,&reference_image->exception);
      reference_image=DestroyImage(reference_image);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      /*
        Ping reference image.
      */
      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      ping_image=PingImage(image_info,exception);
      if (ping_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      ping_image=DestroyImage(ping_image);
      /*
        Read reference image.
      */
      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      reference_image=ReadImage(image_info,exception);
      if (reference_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      /*
        Write reference image.
      */
      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      (void) CopyMagickString(image_info->magick,reference_formats[i].magick,
        MaxTextExtent);
      reference_image->depth=reference_types[j].depth;
      reference_image->compression=reference_formats[i].compression;
      length=8192;
      blob=ImageToBlob(image_info,reference_image,&length,exception);
      if (blob == (unsigned char *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      /*
        Ping reference blob.
      */
      ping_image=PingBlob(image_info,blob,length,exception);
      if (ping_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          blob=(unsigned char *) RelinquishMagickMemory(blob);
          continue;
        }
      ping_image=DestroyImage(ping_image);
      /*
        Read reconstruct image.
      */
      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      reconstruct_image=BlobToImage(image_info,blob,length,exception);
      blob=(unsigned char *) RelinquishMagickMemory(blob);
      if (reconstruct_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      /*
        Compare reference to reconstruct image.
      */
      fuzz=0.003;  /* grayscale */
      if (reference_formats[i].fuzz != 0.0)
        fuzz=reference_formats[i].fuzz;
      difference_image=CompareImageChannels(reference_image,reconstruct_image,
        CompositeChannels,RootMeanSquaredErrorMetric,&distortion,exception);
      reconstruct_image=DestroyImage(reconstruct_image);
      reference_image=DestroyImage(reference_image);
      if (difference_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      difference_image=DestroyImage(difference_image);
      if ((QuantumScale*distortion) > fuzz)
        {
          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
            QuantumScale*distortion);
          (*fail)++;
          continue;
        }

#ifdef MagickCountTempFiles
      (void) FormatLocaleFile(stdout,"... pass, ");
      (void) fflush(stdout);
      SystemCommand[0]='\0';
      (void) strncat(SystemCommand,"echo `ls ",9);
      (void) strncat(SystemCommand,path,MaxTextExtent-31);
      (void) strncat(SystemCommand,"* | wc -w` tmp files.",20);
      (void) system(SystemCommand);
      (void) fflush(stdout);
#else
      (void) FormatLocaleFile(stdout,"... pass\n");
#endif
    }
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateImageFormatsOnDisk() validates the ImageMagick image formats on disk
%  and returns the number of validation tests that passed and failed.
%
%  The format of the ValidateImageFormatsOnDisk method is:
%
%      size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  char
    size[MaxTextExtent];

  const MagickInfo
    *magick_info;

  double
    distortion,
    fuzz;

  Image
    *difference_image,
    *reference_image,
    *reconstruct_image;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    test;

  test=0;
  (void) FormatLocaleFile(stdout,"validate image formats on disk:\n");
  for (i=0; reference_formats[i].magick != (char *) NULL; i++)
  {
    magick_info=GetMagickInfo(reference_formats[i].magick,exception);
    if ((magick_info == (const MagickInfo *) NULL) ||
        (magick_info->decoder == (DecodeImageHandler *) NULL) ||
        (magick_info->encoder == (EncodeImageHandler *) NULL))
      continue;
    for (j=0; reference_types[j].type != UndefinedType; j++)
    {
      /*
        Generate reference image.
      */
      CatchException(exception);
      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
        (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
        MagickCompressOptions,reference_formats[i].compression),
        CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
        (double) reference_types[j].depth);
      (void) CopyMagickString(image_info->filename,reference_filename,
        MaxTextExtent);
      reference_image=ReadImage(image_info,exception);
      if (reference_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      /*
        Write reference image.
      */
      (void) FormatLocaleString(size,MaxTextExtent,"%.20gx%.20g",
        (double) reference_image->columns,(double) reference_image->rows);
      (void) CloneString(&image_info->size,size);
      image_info->depth=reference_types[j].depth;
      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      status=SetImageType(reference_image,reference_types[j].type);
      InheritException(exception,&reference_image->exception);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      status=SetImageDepth(reference_image,reference_types[j].depth);
      InheritException(exception,&reference_image->exception);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      reference_image->compression=reference_formats[i].compression;
      status=WriteImage(image_info,reference_image);
      InheritException(exception,&reference_image->exception);
      reference_image=DestroyImage(reference_image);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      /*
        Read reference image.
      */
      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      reference_image=ReadImage(image_info,exception);
      if (reference_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      /*
        Write reference image.
      */
      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      reference_image->depth=reference_types[j].depth;
      reference_image->compression=reference_formats[i].compression;
      status=WriteImage(image_info,reference_image);
      InheritException(exception,&reference_image->exception);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      /*
        Read reconstruct image.
      */
      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
        reference_formats[i].magick,output_filename);
      reconstruct_image=ReadImage(image_info,exception);
      if (reconstruct_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      /*
        Compare reference to reconstruct image.
      */
      fuzz=0.003;  /* grayscale */
      if (reference_formats[i].fuzz != 0.0)
        fuzz=reference_formats[i].fuzz;
      difference_image=CompareImageChannels(reference_image,reconstruct_image,
        CompositeChannels,RootMeanSquaredErrorMetric,&distortion,exception);
      reconstruct_image=DestroyImage(reconstruct_image);
      reference_image=DestroyImage(reference_image);
      if (difference_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      difference_image=DestroyImage(difference_image);
      if ((QuantumScale*distortion) > fuzz)
        {
          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
            QuantumScale*distortion);
          (*fail)++;
          continue;
        }
      (void) FormatLocaleFile(stdout,"... pass.\n");
    }
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateImportExportPixels() validates the pixel import and export methods.
%  It returns the number of validation tests that passed and failed.
%
%  The format of the ValidateImportExportPixels method is:
%
%      size_t ValidateImportExportPixels(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static size_t ValidateImportExportPixels(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  double
    distortion;

  Image
    *difference_image,
    *reference_image,
    *reconstruct_image;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    length;

  unsigned char
    *pixels;

  size_t
    test;

  (void) output_filename;
  test=0;
  (void) FormatLocaleFile(stdout,
    "validate the import and export of image pixels:\n");
  for (i=0; reference_map[i] != (char *) NULL; i++)
  {
    for (j=0; reference_storage[j].type != UndefinedPixel; j++)
    {
      /*
        Generate reference image.
      */
      CatchException(exception);
      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s",(double) (test++),
        reference_map[i],CommandOptionToMnemonic(MagickStorageOptions,
        reference_storage[j].type));
      (void) CopyMagickString(image_info->filename,reference_filename,
        MaxTextExtent);
      reference_image=ReadImage(image_info,exception);
      if (reference_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      if (LocaleNCompare(reference_map[i],"cmy",3) == 0)
        (void) TransformImageColorspace(reference_image,CMYKColorspace);
      length=strlen(reference_map[i])*reference_image->columns*
        reference_image->rows*reference_storage[j].quantum;
      pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
      if (pixels == (unsigned char *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      (void) ResetMagickMemory(pixels,0,length*sizeof(*pixels));
      status=ExportImagePixels(reference_image,0,0,reference_image->columns,
        reference_image->rows,reference_map[i],reference_storage[j].type,pixels,
        exception);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          pixels=(unsigned char *) RelinquishMagickMemory(pixels);
          reference_image=DestroyImage(reference_image);
          continue;
        }
      (void) SetImageBackgroundColor(reference_image);
      status=ImportImagePixels(reference_image,0,0,reference_image->columns,
        reference_image->rows,reference_map[i],reference_storage[j].type,
        pixels);
      InheritException(exception,&reference_image->exception);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
           pixels=(unsigned char *) RelinquishMagickMemory(pixels);
          reference_image=DestroyImage(reference_image);
          continue;
        }
      /*
        Read reconstruct image.
      */
      reconstruct_image=AcquireImage(image_info);
      (void) SetImageExtent(reconstruct_image,reference_image->columns,
        reference_image->rows);
      (void) SetImageColorspace(reconstruct_image,reference_image->colorspace);
      (void) SetImageBackgroundColor(reconstruct_image);
      status=ImportImagePixels(reconstruct_image,0,0,reconstruct_image->columns,
        reconstruct_image->rows,reference_map[i],reference_storage[j].type,
        pixels);
      InheritException(exception,&reconstruct_image->exception);
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
      if (status == MagickFalse)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      /*
        Compare reference to reconstruct image.
      */
      difference_image=CompareImageChannels(reference_image,reconstruct_image,
        CompositeChannels,RootMeanSquaredErrorMetric,&distortion,exception);
      reconstruct_image=DestroyImage(reconstruct_image);
      reference_image=DestroyImage(reference_image);
      if (difference_image == (Image *) NULL)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          (*fail)++;
          continue;
        }
      difference_image=DestroyImage(difference_image);
      if ((QuantumScale*distortion) > 0.0)
        {
          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
            QuantumScale*distortion);
          (*fail)++;
          continue;
        }
      (void) FormatLocaleFile(stdout,"... pass.\n");
    }
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   V a l i d a t e M o n t a g e C o m m a n d                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateMontageCommand() validates the ImageMagick montage command line
%  program and returns the number of validation tests that passed and failed.
%
%  The format of the ValidateMontageCommand method is:
%
%      size_t ValidateMontageCommand(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static size_t ValidateMontageCommand(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  char
    **arguments,
    command[MaxTextExtent];

  int
    number_arguments;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    test;

  test=0;
  (void) FormatLocaleFile(stdout,"validate montage command line program:\n");
  for (i=0; montage_options[i] != (char *) NULL; i++)
  {
    CatchException(exception);
    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
      montage_options[i]);
    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
      reference_filename,montage_options[i],reference_filename,
      output_filename);
    arguments=StringToArgv(command,&number_arguments);
    if (arguments == (char **) NULL)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
        (*fail)++;
        continue;
      }
    status=MontageImageCommand(image_info,number_arguments,arguments,
      (char **) NULL,exception);
    for (j=0; j < (ssize_t) number_arguments; j++)
      arguments[j]=DestroyString(arguments[j]);
    arguments=(char **) RelinquishMagickMemory(arguments);
    if (status != MagickFalse)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
        (*fail)++;
        continue;
      }
    (void) FormatLocaleFile(stdout,"... pass.\n");
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   V a l i d a t e S t r e a m C o m m a n d                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ValidateStreamCommand() validates the ImageMagick stream command line
%  program and returns the number of validation tests that passed and failed.
%
%  The format of the ValidateStreamCommand method is:
%
%      size_t ValidateStreamCommand(ImageInfo *image_info,
%        const char *reference_filename,const char *output_filename,
%        size_t *fail,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o reference_filename: the reference image filename.
%
%    o output_filename: the output image filename.
%
%    o fail: return the number of validation tests that pass.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static size_t ValidateStreamCommand(ImageInfo *image_info,
  const char *reference_filename,const char *output_filename,size_t *fail,
  ExceptionInfo *exception)
{
  char
    **arguments,
    command[MaxTextExtent];

  int
    number_arguments;

  MagickBooleanType
    status;

  register ssize_t
    i,
    j;

  size_t
    test;

  test=0;
  (void) FormatLocaleFile(stdout,"validate stream command line program:\n");
  for (i=0; stream_options[i] != (char *) NULL; i++)
  {
    CatchException(exception);
    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
      stream_options[i]);
    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s",
      stream_options[i],reference_filename,output_filename);
    arguments=StringToArgv(command,&number_arguments);
    if (arguments == (char **) NULL)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
        (*fail)++;
        continue;
      }
    status=StreamImageCommand(image_info,number_arguments,arguments,
      (char **) NULL,exception);
    for (j=0; j < (ssize_t) number_arguments; j++)
      arguments[j]=DestroyString(arguments[j]);
    arguments=(char **) RelinquishMagickMemory(arguments);
    if (status != MagickFalse)
      {
        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
        (*fail)++;
        continue;
      }
    (void) FormatLocaleFile(stdout,"... pass.\n");
  }
  (void) FormatLocaleFile(stdout,
    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
    (double) (test-(*fail)),(double) *fail);
  return(test);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%  M a i n                                                                    %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/

static MagickBooleanType ValidateUsage(void)
{
  const char
    **p;

  static const char
    *miscellaneous[]=
    {
      "-debug events        display copious debugging information",
      "-help                print program options",
      "-log format          format of debugging information",
      "-validate type       validation type",
      "-version             print version information",
      (char *) NULL
    },
    *settings[]=
    {
      "-regard-warnings     pay attention to warning messages",
      "-verbose             print detailed information about the image",
      (char *) NULL
    };

  (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
  (void) printf("Copyright: %s\n\n",GetMagickCopyright());
  (void) printf("Features: %s\n",GetMagickFeatures());
  (void) printf("Usage: %s [options ...] reference-file\n",GetClientName());
  (void) printf("\nValidate Settings:\n");
  for (p=settings; *p != (char *) NULL; p++)
    (void) printf("  %s\n",*p);
  (void) printf("\nMiscellaneous Options:\n");
  for (p=miscellaneous; *p != (char *) NULL; p++)
    (void) printf("  %s\n",*p);
  return(MagickTrue);
}

int main(int argc,char **argv)
{
#define DestroyValidate() \
{ \
  image_info=DestroyImageInfo(image_info); \
  exception=DestroyExceptionInfo(exception); \
}
#define ThrowValidateException(asperity,tag,option) \
{ \
  (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag,"`%s'", \
    option); \
  CatchException(exception); \
  DestroyValidate(); \
  return(MagickFalse); \
}

  char
    output_filename[MaxTextExtent],
    reference_filename[MaxTextExtent],
    *option;

  double
    elapsed_time,
    user_time;

  ExceptionInfo
    *exception;

  Image
    *reference_image;

  ImageInfo
    *image_info;

  MagickBooleanType
    regard_warnings,
    status;

  MagickSizeType
    memory_resource,
    map_resource;

  register ssize_t
    i;

  TimerInfo
    *timer;

  size_t
    fail,
    iterations,
    tests;

  ValidateType
    type;

  /*
    Validate the ImageMagick image processing suite.
  */
  MagickCoreGenesis(*argv,MagickTrue);
  (void) setlocale(LC_ALL,"");
  (void) setlocale(LC_NUMERIC,"C");
  iterations=1;
  status=MagickFalse;
  type=AllValidate;
  regard_warnings=MagickFalse;
  (void) regard_warnings;
  exception=AcquireExceptionInfo();
  image_info=AcquireImageInfo();
  (void) CopyMagickString(image_info->filename,ReferenceFilename,MaxTextExtent);
  for (i=1; i < (ssize_t) argc; i++)
  {
    option=argv[i];
    if (IsCommandOption(option) == MagickFalse)
      {
        (void) CopyMagickString(image_info->filename,option,MaxTextExtent);
        continue;
      }
    switch (*(option+1))
    {
      case 'b':
      {
        if (LocaleCompare("bench",option+1) == 0)
          {
            iterations=StringToUnsignedLong(argv[++i]);
            break;
          }
        ThrowValidateException(OptionError,"UnrecognizedOption",option)
      }
      case 'd':
      {
        if (LocaleCompare("debug",option+1) == 0)
          {
            (void) SetLogEventMask(argv[++i]);
            break;
          }
        ThrowValidateException(OptionError,"UnrecognizedOption",option)
      }
      case 'h':
      {
        if (LocaleCompare("help",option+1) == 0)
          {
            (void) ValidateUsage();
            return(0);
          }
        ThrowValidateException(OptionError,"UnrecognizedOption",option)
      }
      case 'l':
      {
        if (LocaleCompare("log",option+1) == 0)
          {
            if (*option != '+')
              (void) SetLogFormat(argv[i+1]);
            break;
          }
        ThrowValidateException(OptionError,"UnrecognizedOption",option)
      }
      case 'r':
      {
        if (LocaleCompare("regard-warnings",option+1) == 0)
          {
            regard_warnings=MagickTrue;
            break;
          }
        ThrowValidateException(OptionError,"UnrecognizedOption",option)
      }
      case 'v':
      {
        if (LocaleCompare("validate",option+1) == 0)
          {
            ssize_t
              validate;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowValidateException(OptionError,"MissingArgument",option);
            validate=ParseCommandOption(MagickValidateOptions,MagickFalse,
              argv[i]);
            if (validate < 0)
              ThrowValidateException(OptionError,"UnrecognizedValidateType",
                argv[i]);
            type=(ValidateType) validate;
            break;
          }
        if ((LocaleCompare("version",option+1) == 0) ||
            (LocaleCompare("-version",option+1) == 0))
          {
            (void) FormatLocaleFile(stdout,"Version: %s\n",
              GetMagickVersion((size_t *) NULL));
            (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
              GetMagickCopyright());
            (void) FormatLocaleFile(stdout,"Features: %s\n\n",
              GetMagickFeatures());
            return(0);
          }
        ThrowValidateException(OptionError,"UnrecognizedOption",option)
      }
      default:
        ThrowValidateException(OptionError,"UnrecognizedOption",option)
    }
  }
  timer=(TimerInfo *) NULL;
  if (iterations > 1)
    timer=AcquireTimerInfo();
  reference_image=ReadImage(image_info,exception);
  tests=0;
  fail=0;
  if (reference_image == (Image *) NULL)
    fail++;
  else
    {
      if (LocaleCompare(image_info->filename,ReferenceFilename) == 0)
        (void) CopyMagickString(reference_image->magick,ReferenceImageFormat,
          MaxTextExtent);
      (void) AcquireUniqueFilename(reference_filename);
      (void) AcquireUniqueFilename(output_filename);
      (void) CopyMagickString(reference_image->filename,reference_filename,
        MaxTextExtent);
      status=WriteImage(image_info,reference_image);
      InheritException(exception,&reference_image->exception);
      reference_image=DestroyImage(reference_image);
      if (status == MagickFalse)
        fail++;
      else
        {
          (void) FormatLocaleFile(stdout,"Version: %s\n",
            GetMagickVersion((size_t *) NULL));
          (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
            GetMagickCopyright());
          (void) FormatLocaleFile(stdout,
            "ImageMagick Validation Suite (%s)\n\n",CommandOptionToMnemonic(
            MagickValidateOptions,(ssize_t) type));
          if ((type & ColorspaceValidate) != 0)
            tests+=ValidateColorspaces(image_info,&fail,exception);
          if ((type & CompareValidate) != 0)
            tests+=ValidateCompareCommand(image_info,reference_filename,
              output_filename,&fail,exception);
          if ((type & CompositeValidate) != 0)
            tests+=ValidateCompositeCommand(image_info,reference_filename,
              output_filename,&fail,exception);
          if ((type & ConvertValidate) != 0)
            tests+=ValidateConvertCommand(image_info,reference_filename,
              output_filename,&fail,exception);
          if ((type & FormatsDiskValidate) != 0)
            {
              memory_resource=SetMagickResourceLimit(MemoryResource,0);
              map_resource=SetMagickResourceLimit(MapResource,0);
              (void) FormatLocaleFile(stdout,"[pixel-cache: disk] ");
              tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
                output_filename,&fail,exception);
              (void) FormatLocaleFile(stdout,"[pixel-cache: disk] ");
              tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
                output_filename,&fail,exception);
              (void) SetMagickResourceLimit(MemoryResource,memory_resource);
              (void) SetMagickResourceLimit(MapResource,map_resource);
            }
          if ((type & FormatsMapValidate) != 0)
            {
              memory_resource=SetMagickResourceLimit(MemoryResource,0);
              (void) FormatLocaleFile(stdout,"[pixel-cache: memory-mapped] ");
              tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
                output_filename,&fail,exception);
              (void) FormatLocaleFile(stdout,"[pixel-cache: memory-mapped] ");
              tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
                output_filename,&fail,exception);
              (void) SetMagickResourceLimit(MemoryResource,memory_resource);
            }
          if ((type & FormatsMemoryValidate) != 0)
            {
              (void) FormatLocaleFile(stdout,"[pixel-cache: memory] ");
              tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
                output_filename,&fail,exception);
              (void) FormatLocaleFile(stdout,"[pixel-cache: memory] ");
              tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
                output_filename,&fail,exception);
            }
          if ((type & IdentifyValidate) != 0)
            tests+=ValidateIdentifyCommand(image_info,reference_filename,
              output_filename,&fail,exception);
          if ((type & ImportExportValidate) != 0)
            tests+=ValidateImportExportPixels(image_info,reference_filename,
              output_filename,&fail,exception);
          if ((type & MontageValidate) != 0)
            tests+=ValidateMontageCommand(image_info,reference_filename,
              output_filename,&fail,exception);
          if ((type & StreamValidate) != 0)
            tests+=ValidateStreamCommand(image_info,reference_filename,
              output_filename,&fail,exception);
          (void) FormatLocaleFile(stdout,
            "validation suite: %.20g tests; %.20g passed; %.20g failed.\n",
            (double) tests,(double) (tests-fail),(double) fail);
        }
      (void) RelinquishUniqueFileResource(output_filename);
      (void) RelinquishUniqueFileResource(reference_filename);
    }
  if (exception->severity != UndefinedException)
    CatchException(exception);
  if (iterations > 1)
    {
      elapsed_time=GetElapsedTime(timer);
      user_time=GetUserTime(timer);
      (void) FormatLocaleFile(stderr,
        "Performance: %.20gi %gips %0.3fu %ld:%02ld.%03ld\n",(double)
        iterations,1.0*iterations/elapsed_time,user_time,(long)
        (elapsed_time/60.0),(long) ceil(fmod(elapsed_time,60.0)),
        (long) (1000.0*(elapsed_time-floor(elapsed_time))));
      timer=DestroyTimerInfo(timer);
    }
  DestroyValidate();
  MagickCoreTerminus();
  return(fail == 0 ? 0 : 1);
}

/* [<][>][^][v][top][bottom][index][help] */