// clrspace.h
#if !defined(CLRSPACE_H)
#define CLRSPACE_H
#include <math.h> // for sqrt(), atan2(), and M_PI
// Some color spaces in current use including transformations
// between them. Type T is assumed to be a floating point type
// (float, double, or long double). This library can be extended
// to integer types by writing class specializations.
namespace clrspace {
template <class T>
class Color1 { // base class for 1-D color spaces
protected:
T
_zeta1; // coordinate value
public:
Color1() {}
Color1 (T izeta1) : _zeta1(izeta1) {}
T // generic coordinate name (mostly for internal use)
zeta1() const {return _zeta1;}
};
template <class T>
class Color2 : public Color1<T> { // base class for
protected: // 2-D color spaces
T
_zeta2; // second coordinate
public:
Color2() {}
Color2 (T izeta1, T izeta2) :
Color1<T>(izeta1), _zeta2(izeta2) {}
T // generic coordinate name (mostly for internal use)
zeta2() const {return _zeta2;}
};
template <class T>
class Color3 : public Color2<T> { // base class for
protected: // 3-D color spaces
T
_zeta3; // third coordinate
public:
Color3() {}
Color3 (T izeta1, T izeta2, T izeta3) :
Color2<T>(izeta1,izeta2), _zeta3(izeta3) {}
T // generic coordinate name (mostly for internal use)
zeta3() const {return _zeta3;}
};
// by definition, all "colorimetric" color spaces can be
// transformed to XYZ
template <class T>
class XYZ : public Color3<T> { // CIE (X,Y,Z) space
public:
XYZ() {}
XYZ (T ix, T iy, T iz) : Color3<T>(ix,iy,iz) {}
T X() const {return _zeta1;}
T Y() const {return _zeta2;}
T Z() const {return _zeta3;}
};
// ~~~~~Brightness and Lightness Spaces~~~~~
template <class T>
class CIE_L; // forward reference
// two colors with equal Y values appear equally bright
template <class T>
class CIE_Y : public Color1<T> { // same as Y() from XYZ
public:
CIE_Y() {}
CIE_Y (T iY) : Color1<T>(iY) {}
CIE_Y (const CIE_L<T> &L, const CIE_Y<T> &Yn); // Yn ==
// white ref.
T // read access to CIE Y coordinate
Y() const {return _zeta1;}
};
// lightness is brightness judged in comparison to a
// white reference
template <class T>
class CIE_L : public Color1<T> { // CIE L* lightness metric
public:
CIE_L() {}
CIE_L (T iL) : Color1<T>(iL) {}
CIE_L (const CIE_Y<T> &Y, const CIE_Y<T> &Yn); // Yn ==
// white ref.
T // read access to CIE L* coordinate
L() const {return _zeta1;}
};
//~~~~~chromaticity coordinates~~~~~
// a chromaticity space is normalized so that the three
// coordinates add to 1
template <class T>
class ChromaticitySpace : public Color2<T> { // only two
// coordinates are
// stored
protected:
T // compute the redundant third coordinate
zeta3() const;
public:
ChromaticitySpace() {}
ChromaticitySpace (T izeta1, T izeta2) :
Color2<T>(izeta1,izeta2) {}
};
// normalized XYZ space
template <class T>
class xy : public ChromaticitySpace<T> { // CIE xyz color space
public:
xy() {}
xy (T ix, T iy) : ChromaticitySpace<T>(ix,iy) {}
xy (const uvPrime<T> &); // convert from CIE u'v'w'
xy (const XYZ<T> &xyz); // convert from CIE XYZ
XYZ<T> // convert to CIE XYZ
toXYZ (const CIE_Y<T> &Y) const; // argument means no
// operator XYZ<T>
T x() const {return _zeta1;} // read access to x
T y() const {return _zeta2;} // read access to y
T z() const {return zeta3();} // compute 1 - x - y
};
// more perceptually flat than xy<T>
template <class T>
class uvPrime : public ChromaticitySpace<T> { // CIE u'v'w'
// color space
public:
uvPrime() {}
uvPrime (T iuPrime, T ivPrime) :
ChromaticitySpace<T>(iuPrime,ivPrime) {}
uvPrime (const xy<T> &); // convert from CIE xyz
uvPrime (const XYZ<T> &xyz); // convert from CIE XYZ
XYZ<T> toXYZ (const CIE_Y<T> &Y) const // convert to CIE XYZ
{return xy<T>(*this).toXYZ(Y);}
T uPrime() const {return _zeta1;} // read access to uPrime
T vPrime() const {return _zeta2;} // read access to vPrime
T wPrime() const {return zeta3();} // compute 1-uPrime-vPrime
};
// ~~~~~RGBBase family of color spaces~~~~~
// RGBBase means red, green, blue
template <class T>
class RGBBase : public Color3<T> { // uncalibrated (R,G,B) space
public:
RGBBase() {}
RGBBase (T ir, T ig, T ib) : Color3<T>(ir,ig,ib) {}
T R() const {return _zeta1;}
T G() const {return _zeta2;}
T B() const {return _zeta3;}
};
// An RGBConv<T,CONV> is an RGBBase<T> having a static CONV
template <class T, class CONV> // CONV derived from ConvertRGB<T>
class RGBConv : public RGBBase<T> { // base class for RGBLinear
// and RGBGamma
protected:
static const CONV // XYZ and Gamma conversions
_conv;
public:
RGBConv() {}
RGBConv (T ir, T ig, T ib) : RGBBase<T>(ir,ig,ib) {}
RGBConv (const RGBBase<T> &rgb) : RGBBase<T>(rgb) {}
};
template <class T, class CONV>
class RGBGamma; // forward reference
// RGBLinear<T,CONV> is a base class for a linear-light
// RGBBase space
template <class T, class CONV>
class RGBLinear : public RGBConv<T,CONV> {
protected:
RGBLinear (const RGBBase<T> &rgb) : // for internal use only
RGBConv<T,CONV>(rgb.R(),rgb.G(),rgb.B()) {}
public:
RGBLinear() {}
RGBLinear (T ir, T ig, T ib) : RGBConv<T,CONV>(ir,ig,ib) {}
RGBLinear (const RGBGamma<T,CONV> &rgbgam) :
RGBConv<T,CONV>(_conv.fromGamma(rgbgam)) {}
RGBLinear (const XYZ<T> &xyz) :
RGBConv<T,CONV>(_conv.fromXYZ(xyz)) {}
XYZ<T> // explicit conversion to XYZ
toXYZ() const {return _conv.toXYZ(*this);}
operator // implicit converstion to XYZ
XYZ<T> () const {return toXYZ();}
};
// RGBLinear<T,CONV> is a base class for a gamma-corrected
// RGBBase space
template <class T, class CONV>
class RGBGamma : public RGBConv<T,CONV> { // gamma corrected
// (R,G,B) space
protected:
RGBGamma (const RGBBase<T> &rgb) :
RGBConv<T,CONV>(rgb.R(),rgb.G(),rgb.B()) {}
public:
RGBGamma() {}
RGBGamma (T ir, T ig, T ib) : RGBConv<T,CONV>(ir,ig,ib) {}
RGBGamma (const RGBLinear<T,CONV> &rgblin) :
RGBConv<T,CONV>(_conv.toGamma(rgblin)) {}
RGBGamma (const XYZ<T> &xyz) :
RGBConv<T,CONV>(_conv.toGamma(_conv.fromXYZ(xyz))) {}
XYZ<T> toXYZ() const // explicit conversion to XYZ
{return _conv.toXYZ(_conv.fromGamma(*this));}
operator XYZ<T> () const // implicit conversion to XYZ
{return toXYZ();}
};
//~~~~~RGB709<T>: an example use of RGBLinear<T> and ~~~~~
// RGBGamma<T>
// step 1: derive a conversion class with a default constructor
template <class T> // needs to be changed if T is an integer type
class Convert_RGB709 : public ConvertRGB<T> {
public:
// RGB709 is a proposed HDTV standard (ITU.BT-709)
Convert_RGB709() : ConvertRGB<T>
(
xy<T>(0.64,0.33), // red chromaticity
xy<T>(0.30,0.60), // green chromaticity
xy<T>(0.15,0.06), // blue chromaticity
D65<T>(), // white point chromaticity
1.0/0.45, // gamma
0.018 // epsilon
) {}
};
template <class T>
class RGB709; // forward reference
// step 2: derive a new linear-light RGBBase space using the
// converter from step 1
template <class T>
class RGB709Linear : public RGBLinear<T,Convert_RGB709<T> > {
public:
RGB709Linear() {}
RGB709Linear (T ir, T ig, T ib) :
RGBLinear<T,Convert_RGB709<T> >(ir,ig,ib) {}
RGB709Linear (const RGB709<T> &gamma) :
RGBLinear<T,Convert_RGB709<T> >(gamma) {}
RGB709Linear (const XYZ<T> &xyz) :
RGBLinear<T,Convert_RGB709<T> >(xyz) {}
};
// step 3: derive an associated gamma-corrected RGBBase space
template <class T>
class RGB709 : public RGBGamma<T,Convert_RGB709<T> > {
public:
RGB709() {}
RGB709 (T ir, T ig, T ib) :
RGBGamma<T,Convert_RGB709<T> >(ir,ig,ib) {}
RGB709 (const RGB709Linear<T> &linear) :
RGBGamma<T,Convert_RGB709<T> >(linear) {}
RGB709 (const XYZ<T> &xyz) :
RGBGamma<T,Convert_RGB709<T> >(xyz) {}
};
#endif
/* End of File */