% Graphic Gems - Graphic Support Methods %
% %
% Software Design %
-% John Cristy %
+% Cristy %
% August 1996 %
% %
% %
-% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2014 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 %
%
% A description of each parameter follows:
%
-% o hue, chroma, luma: A double value representing a
-% component of the HCL color space.
+% o hue, chroma, luma: A double value representing a component of the
+% HCL color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
MagickPrivate void ConvertHCLToRGB(const double hue,const double chroma,
const double luma,double *red,double *green,double *blue)
+{
+ double
+ b,
+ c,
+ g,
+ h,
+ m,
+ r,
+ x;
+
+ /*
+ Convert HCL to RGB colorspace.
+ */
+ assert(red != (double *) NULL);
+ assert(green != (double *) NULL);
+ assert(blue != (double *) NULL);
+ h=6.0*hue;
+ c=chroma;
+ x=c*(1.0-fabs(fmod(h,2.0)-1.0));
+ r=0.0;
+ g=0.0;
+ b=0.0;
+ if ((0.0 <= h) && (h < 1.0))
+ {
+ r=c;
+ g=x;
+ }
+ else
+ if ((1.0 <= h) && (h < 2.0))
+ {
+ r=x;
+ g=c;
+ }
+ else
+ if ((2.0 <= h) && (h < 3.0))
+ {
+ g=c;
+ b=x;
+ }
+ else
+ if ((3.0 <= h) && (h < 4.0))
+ {
+ g=x;
+ b=c;
+ }
+ else
+ if ((4.0 <= h) && (h < 5.0))
+ {
+ r=x;
+ b=c;
+ }
+ else
+ if ((5.0 <= h) && (h < 6.0))
+ {
+ r=c;
+ b=x;
+ }
+ m=luma-(0.298839*r+0.586811*g+0.114350*b);
+ *red=QuantumRange*(r+m);
+ *green=QuantumRange*(g+m);
+ *blue=QuantumRange*(b+m);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% C o n v e r t H C L p T o R G B %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ConvertHCLpToRGB() transforms a (hue, chroma, luma) to a (red, green,
+% blue) triple. Since HCL colorspace is wider than RGB, we instead choose a
+% saturation strategy to project it on the RGB cube.
+%
+% The format of the ConvertHCLpToRGBImage method is:
+%
+% void ConvertHCLpToRGB(const double hue,const double chroma,
+% const double luma,double *red,double *green,double *blue)
+%
+% A description of each parameter follows:
+%
+% o hue, chroma, luma: A double value representing a componenet of the
+% HCLp color space.
+%
+% o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+MagickPrivate void ConvertHCLpToRGB(const double hue,const double chroma,
+ const double luma,double *red,double *green,double *blue)
{
double
b,
z;
/*
- Convert HCL to RGB colorspace.
+ Convert HCLp to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
r=c;
b=x;
}
- m=luma-(0.298839f*r+0.586811f*g+0.114350f*b);
+ m=luma-(0.298839*r+0.586811*g+0.114350*b);
z=1.0;
if (m < 0.0)
{
const double intensity,double *red,double *green,double *blue)
{
double
- h;
+ b,
+ g,
+ h,
+ r;
/*
Convert HSI to RGB colorspace.
h-=360.0*floor(h/360.0);
if (h < 120.0)
{
- *blue=intensity*(1.0-saturation);
- *red=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
+ b=intensity*(1.0-saturation);
+ r=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
(MagickPI/180.0)));
- *green=3.0*intensity-*red-*blue;
+ g=3.0*intensity-r-b;
}
else
if (h < 240.0)
{
h-=120.0;
- *red=intensity*(1.0-saturation);
- *green=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
+ r=intensity*(1.0-saturation);
+ g=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
(MagickPI/180.0)));
- *blue=3.0*intensity-*red-*green;
+ b=3.0*intensity-r-g;
}
else
{
h-=240.0;
- *green=intensity*(1.0-saturation);
- *blue=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
+ g=intensity*(1.0-saturation);
+ b=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
(MagickPI/180.0)));
- *red=3.0*intensity-*green-*blue;
+ r=3.0*intensity-g-b;
}
- *red*=QuantumRange;
- *green*=QuantumRange;
- *blue*=QuantumRange;
+ *red=QuantumRange*r;
+ *green=QuantumRange*g;
+ *blue=QuantumRange*b;
}
\f
/*
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
+
+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);
+}
+
MagickPrivate void ConvertLCHabToRGB(const double luma,const double chroma,
const double hue,double *red,double *green,double *blue)
{
double
- a,
- b,
- C,
- H,
- L,
X,
Y,
Z;
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
- L=luma;
- C=chroma;
- H=hue;
- a=C*cos(360.0*H*MagickPI/180.0);
- b=C*sin(360.0*H*MagickPI/180.0);
- ConvertLabToXYZ(((116.0*L)-16.0)/100.0,(500.0*a)/255.0+0.5,(200.0*b)/255.0+
- 0.5,&X,&Y,&Z);
+ ConvertLCHabToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
ConvertXYZToRGB(X,Y,Z,red,green,blue);
}
\f
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
+
+static inline void ConvertLCHuvToXYZ(const double luma,const double chroma,
+ const double hue,double *X,double *Y,double *Z)
+{
+ ConvertLuvToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
+ sin(hue*MagickPI/180.0),X,Y,Z);
+}
+
MagickPrivate void ConvertLCHuvToRGB(const double luma,const double chroma,
const double hue,double *red,double *green,double *blue)
{
double
- C,
- H,
- L,
- u,
- v,
X,
Y,
Z;
assert(red != (double *) NULL);
assert(green != (double *) NULL);
assert(blue != (double *) NULL);
- L=luma;
- C=chroma;
- H=hue;
- u=C*cos(360.0*H*MagickPI/180.0);
- v=C*sin(360.0*H*MagickPI/180.0);
- ConvertLuvToXYZ(L,(u+1.34)/3.54,(v+1.4)/2.62,&X,&Y,&Z);
+ ConvertLCHuvToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
ConvertXYZToRGB(X,Y,Z,red,green,blue);
}
\f
h=((r-g)/c)+4.0;
*hue=(h/6.0);
*chroma=QuantumScale*c;
- *luma=QuantumScale*(0.298839f*r+0.586811f*g+0.114350f*b);
+ *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
+% C o n v e r t R G B T o H C L p %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ConvertRGBToHCLp() transforms a (red, green, blue) to a (hue, chroma,
+% luma) triple.
+%
+% The format of the ConvertRGBToHCLp method is:
+%
+% void ConvertRGBToHCLp(const double red,const double green,
+% const double blue,double *hue,double *chroma,double *luma)
+%
+% A description of each parameter follows:
+%
+% o red, green, blue: A Quantum value representing the red, green, and
+% blue component of a pixel.
+%
+% o hue, chroma, luma: A pointer to a double value representing a
+% component of the HCL color space.
+%
+*/
+MagickPrivate void ConvertRGBToHCLp(const double red,const double green,
+ const double blue,double *hue,double *chroma,double *luma)
+{
+ double
+ b,
+ c,
+ g,
+ h,
+ max,
+ r;
+
+ /*
+ Convert RGB to HCL colorspace.
+ */
+ assert(hue != (double *) NULL);
+ assert(chroma != (double *) NULL);
+ assert(luma != (double *) NULL);
+ r=red;
+ g=green;
+ b=blue;
+ max=MagickMax(r,MagickMax(g,b));
+ c=max-(double) MagickMin(r,MagickMin(g,b));
+ h=0.0;
+ if (c == 0.0)
+ h=0.0;
+ else
+ if (red == max)
+ h=fmod((g-b)/c+6.0,6.0);
+ else
+ if (green == max)
+ h=((b-r)/c)+2.0;
+ else
+ if (blue == max)
+ h=((r-g)/c)+4.0;
+ *hue=(h/6.0);
+ *chroma=QuantumScale*c;
+ *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
}
\f
/*
*saturation=1.0-MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
QuantumScale*blue))/(*intensity);
alpha=0.5*(2.0*QuantumScale*red-QuantumScale*green-QuantumScale*blue);
- beta=0.866025403784439*(QuantumScale*green-QuantumScale*blue);
+ beta=0.8660254037844385*(QuantumScale*green-QuantumScale*blue);
*hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
if (*hue < 0.0)
*hue+=1.0;
% component of the LCH color space.
%
*/
+
+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;
+}
+
MagickPrivate void ConvertRGBToLCHab(const double red,const double green,
const double blue,double *luma,double *chroma,double *hue)
{
double
- a,
- b,
- C,
- H,
- L,
X,
Y,
Z;
assert(chroma != (double *) NULL);
assert(hue != (double *) NULL);
ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
- ConvertXYZToLab(X,Y,Z,&L,&a,&b);
- C=hypot(255.0*(a-0.5)/500.0,255.0*(b-0.5)/200.0);
- H=180.0*atan2(255.0*(b-0.5)/200.0,255.0*(a-0.5)/500.0)/MagickPI/360.0;
- if (H < 0.0)
- H+=1.0;
- if (H >= 1.0)
- H-=1.0;
- *luma=(100.0*L+16.0)/116.0;
- *chroma=C;
- *hue=H;
+ ConvertXYZToLCHab(X,Y,Z,luma,chroma,hue);
}
\f
/*
% component of the LCHuv color space.
%
*/
+
+static inline void ConvertXYZToLCHuv(const double X,const double Y,
+ const double Z,double *luma,double *chroma,double *hue)
+{
+ double
+ u,
+ v;
+
+ ConvertXYZToLuv(X,Y,Z,luma,&u,&v);
+ *chroma=hypot(354.0*u-134.0,262.0*v-140.0)/255.0+0.5;
+ *hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI/360.0;
+ if (*hue < 0.0)
+ *hue+=1.0;
+}
+
MagickPrivate void ConvertRGBToLCHuv(const double red,const double green,
const double blue,double *luma,double *chroma,double *hue)
{
double
- C,
- H,
- L,
- u,
- v,
X,
Y,
Z;
assert(chroma != (double *) NULL);
assert(hue != (double *) NULL);
ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
- ConvertXYZToLuv(X,Y,Z,&L,&u,&v);
- C=hypot(3.54*u-1.34,2.62*v-1.4);
- H=180.0*atan2(2.62*v-1.4,3.54*u-1.34)/MagickPI/360.0;
- if (H < 0.0)
- H+=1.0;
- if (H >= 1.0)
- H-=1.0;
- *luma=L;
- *chroma=C;
- *hue=H;
+ ConvertXYZToLCHuv(X,Y,Z,luma,chroma,hue);
}
\f
/*