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. ConvertLMSToXYZ
  12. ConvertLMSToRGB
  13. ConvertXYZToLMS
  14. ConvertRGBToLMS
  15. ConvertXYZToLuv
  16. ConvertRGBToLuv
  17. ConvertLuvToXYZ
  18. ConvertLuvToRGB
  19. ConvertRGBToYDbDr
  20. ConvertYDbDrToRGB
  21. ConvertRGBToYIQ
  22. ConvertYIQToRGB
  23. ConvertRGBToYUV
  24. ConvertYUVToRGB
  25. ValidateHSIToRGB
  26. ValidateRGBToHSI
  27. ValidateHSLToRGB
  28. ValidateRGBToHSL
  29. ValidateHSVToRGB
  30. ValidateRGBToHSV
  31. ValidateRGBToJPEGYCbCr
  32. ValidateJPEGYCbCrToRGB
  33. ValidateLabToRGB
  34. ValidateRGBToLab
  35. ValidateLchToRGB
  36. ValidateRGBToLch
  37. ValidateRGBToLMS
  38. ValidateLMSToRGB
  39. ValidateRGBToLuv
  40. ValidateLuvToRGB
  41. ValidateRGBToXYZ
  42. ValidateXYZToRGB
  43. ValidateYDbDrToRGB
  44. ValidateRGBToYDbDr
  45. ValidateRGBToYIQ
  46. ValidateYIQToRGB
  47. ValidateRGBToYPbPr
  48. ValidateYPbPrToRGB
  49. ValidateRGBToYUV
  50. ValidateYUVToRGB
  51. ValidateColorspaces
  52. ValidateCompareCommand
  53. ValidateCompositeCommand
  54. ValidateConvertCommand
  55. ValidateIdentifyCommand
  56. ValidateImageFormatsInMemory
  57. ValidateImageFormatsOnDisk
  58. ValidateImportExportPixels
  59. ValidateMontageCommand
  60. ValidateStreamCommand
  61. ValidateUsage
  62. 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                                 %
%                                  Cristy                                     %
%                               March 2001                                    %
%                                                                             %
%                                                                             %
%  Copyright 1999-2016 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 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 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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      status=SetImageDepth(reference_image,reference_types[j].depth);
      InheritException(exception,&reference_image->exception);
      if (status == MagickFalse || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      /*
        Ping reference blob.
      */
      ping_image=PingBlob(image_info,blob,length,exception);
      if (ping_image == (Image *) NULL ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*fail)++;
          reference_image=DestroyImage(reference_image);
          continue;
        }
      status=SetImageDepth(reference_image,reference_types[j].depth);
      InheritException(exception,&reference_image->exception);
      if (status == MagickFalse || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*fail)++;
          continue;
        }
      if (LocaleNCompare(reference_map[i],"cmy",3) == 0)
        {
          (void) TransformImageColorspace(reference_image,CMYKColorspace);
          InheritException(exception,&reference_image->exception);
        }
      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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 || exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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 ||
          exception->severity >= ErrorException)
        {
          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
            GetMagickModule());
          CatchException(exception);
          (*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] */