*S=QuantumRange*s;
}
-static inline void ConvertXYZToLuv(const double X,const double Y,const double Z,
- double *L,double *u,double *v)
-{
- double
- alpha;
-
- assert(L != (double *) NULL);
- assert(u != (double *) NULL);
- assert(v != (double *) NULL);
- if ((Y/D65Y) > CIEEpsilon)
- *L=(double) (116.0f*pow(Y/D65Y,1.0/3.0)-16.0f);
- else
- *L=CIEK*(Y/D65Y);
- alpha=PerceptibleReciprocal(X+15.0f*Y+3.0f*Z);
- *u=13.0f*(*L)*((4.0f*alpha*X)-(4.0f*D65X/(D65X+15.0f*D65Y+3.0f*D65Z)));
- *v=13.0f*(*L)*((9.0f*alpha*Y)-(9.0f*D65Y/(D65X+15.0f*D65Y+3.0f*D65Z)));
- *L/=100.0f;
- *u=(*u+134.0f)/354.0f;
- *v=(*v+140.0f)/262.0f;
-}
-
static MagickBooleanType sRGBTransformImage(Image *image,
const ColorspaceType colorspace,ExceptionInfo *exception)
{
return(MagickFalse);
return(status);
}
+ case LCHabColorspace:
+ {
+ /*
+ Transform image from sRGB to LCHab.
+ */
+ if (image->storage_class == PseudoClass)
+ {
+ if (SyncImage(image,exception) == MagickFalse)
+ return(MagickFalse);
+ if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
+ return(MagickFalse);
+ }
+ image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(static,4) shared(status) \
+ magick_threads(image,image,image->rows,1)
+#endif
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ MagickBooleanType
+ sync;
+
+ register ssize_t
+ x;
+
+ register Quantum
+ *restrict q;
+
+ if (status == MagickFalse)
+ continue;
+ q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+ exception);
+ if (q == (Quantum *) NULL)
+ {
+ status=MagickFalse;
+ continue;
+ }
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ double
+ blue,
+ chroma,
+ green,
+ hue,
+ luma,
+ red;
+
+ red=DecodePixelGamma((MagickRealType) GetPixelRed(image,q));
+ green=DecodePixelGamma((MagickRealType) GetPixelGreen(image,q));
+ blue=DecodePixelGamma((MagickRealType) GetPixelBlue(image,q));
+ ConvertRGBToLCHab(red,green,blue,&luma,&chroma,&hue);
+ SetPixelRed(image,ClampToQuantum(QuantumRange*luma),q);
+ SetPixelGreen(image,ClampToQuantum(QuantumRange*chroma),q);
+ SetPixelBlue(image,ClampToQuantum(QuantumRange*hue),q);
+ q+=GetPixelChannels(image);
+ }
+ sync=SyncCacheViewAuthenticPixels(image_view,exception);
+ if (sync == MagickFalse)
+ status=MagickFalse;
+ }
+ image_view=DestroyCacheView(image_view);
+ if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
+ return(MagickFalse);
+ return(status);
+ }
case LCHColorspace:
+ case LCHuvColorspace:
{
/*
- Transform image from sRGB to LCH.
+ Transform image from sRGB to LCHuv.
*/
if (image->storage_class == PseudoClass)
{
red=DecodePixelGamma((MagickRealType) GetPixelRed(image,q));
green=DecodePixelGamma((MagickRealType) GetPixelGreen(image,q));
blue=DecodePixelGamma((MagickRealType) GetPixelBlue(image,q));
- ConvertRGBToLCH(red,green,blue,&luma,&chroma,&hue);
+ ConvertRGBToLCHuv(red,green,blue,&luma,&chroma,&hue);
SetPixelRed(image,ClampToQuantum(QuantumRange*luma),q);
SetPixelGreen(image,ClampToQuantum(QuantumRange*chroma),q);
SetPixelBlue(image,ClampToQuantum(QuantumRange*hue),q);
*Z=(-0.009627608738429)*l-0.005698031216113*m+1.015325639954543*s;
}
-static inline void ConvertLuvToXYZ(const double L,const double u,const double v,
- double *X,double *Y,double *Z)
-{
- assert(X != (double *) NULL);
- assert(Y != (double *) NULL);
- assert(Z != (double *) NULL);
- if ((100.0f*L) > (CIEK*CIEEpsilon))
- *Y=(double) pow(((100.0*L)+16.0)/116.0,3.0);
- else
- *Y=(100.0f*L)/CIEK;
- *X=((*Y*((39.0f*(100.0f*L)/((262.0f*v-140.0f)+13.0f*(100.0f*L)*(9.0f*D65Y/
- (D65X+15.0f*D65Y+3.0f*D65Z))))-5.0f))+5.0f*(*Y))/((((52.0f*(100.0f*L)/
- ((354.0f*u-134.0f)+13.0f*(100.0f*L)*(4.0f*D65X/(D65X+15.0f*D65Y+3.0f*
- D65Z))))-1.0f)/3.0f)-(-1.0f/3.0f));
- *Z=(*X*(((52.0f*(100.0f*L)/((354.0f*u-134.0f)+13.0f*(100.0f*L)*(4.0f*D65X/
- (D65X+15.0f*D65Y+3.0f*D65Z))))-1.0f)/3.0f))-5.0f*(*Y);
-}
-
static inline ssize_t RoundToYCC(const double value)
{
if (value <= 0.0f)
luma=(double) (QuantumScale*GetPixelRed(image,q));
chroma=(double) (QuantumScale*GetPixelGreen(image,q));
hue=(double) (QuantumScale*GetPixelBlue(image,q));
- ConvertLCHToRGB(luma,chroma,hue,&red,&green,&blue);
+ ConvertLCHabToRGB(luma,chroma,hue,&red,&green,&blue);
SetPixelRed(image,ClampToQuantum(EncodePixelGamma(red)),q);
SetPixelGreen(image,ClampToQuantum(EncodePixelGamma(green)),q);
SetPixelBlue(image,ClampToQuantum(EncodePixelGamma(blue)),q);
HWBColorspace,
LabColorspace,
LCHColorspace,
+ LCHabColorspace,
+ LCHuvColorspace,
LogColorspace,
LMSColorspace,
LuvColorspace,
/*
Increase or decrease color luma, chroma, or hue.
*/
- ConvertRGBToLCH(*red,*green,*blue,&luma,&chroma,&hue);
+ ConvertRGBToLCHuv(*red,*green,*blue,&luma,&chroma,&hue);
luma*=0.01*percent_luma;
chroma*=0.01*percent_chroma;
hue+=0.5*(0.01*percent_hue-1.0);
hue+=1.0;
while (hue >= 1.0)
hue-=1.0;
- ConvertLCHToRGB(luma,chroma,hue,red,green,blue);
+ ConvertLCHuvToRGB(luma,chroma,hue,red,green,blue);
}
MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate,
extern "C" {
#endif
+#include "MagickCore/pixel-private.h"
+
#define D65X (0.950456f)
#define D65Y (1.0f)
#define D65Z (1.088754f)
double *),
ConvertHWBToRGB(const double,const double,const double,double *,double *,
double *),
- ConvertLCHToRGB(const double,const double,const double,double *,double *,
+ ConvertLCHabToRGB(const double,const double,const double,double *,double *,
+ double *),
+ ConvertLCHuvToRGB(const double,const double,const double,double *,double *,
double *),
ConvertRGBToHCL(const double,const double,const double,double *,double *,
double *),
double *),
ConvertRGBToHWB(const double,const double,const double,double *,double *,
double *),
- ConvertRGBToLCH(const double,const double,const double,double *,double *,
+ ConvertRGBToLCHab(const double,const double,const double,double *,double *,
+ double *),
+ ConvertRGBToLCHuv(const double,const double,const double,double *,double *,
double *);
static inline void ConvertLabToXYZ(const double L,const double a,const double b,
*Z=D65Z*z;
}
+static inline void ConvertLuvToXYZ(const double L,const double u,const double v,
+ double *X,double *Y,double *Z)
+{
+ assert(X != (double *) NULL);
+ assert(Y != (double *) NULL);
+ assert(Z != (double *) NULL);
+ if ((100.0f*L) > (CIEK*CIEEpsilon))
+ *Y=(double) pow(((100.0*L)+16.0)/116.0,3.0);
+ else
+ *Y=(100.0f*L)/CIEK;
+ *X=((*Y*((39.0f*(100.0f*L)/((262.0f*v-140.0f)+13.0f*(100.0f*L)*(9.0f*D65Y/
+ (D65X+15.0f*D65Y+3.0f*D65Z))))-5.0f))+5.0f*(*Y))/((((52.0f*(100.0f*L)/
+ ((354.0f*u-134.0f)+13.0f*(100.0f*L)*(4.0f*D65X/(D65X+15.0f*D65Y+3.0f*
+ D65Z))))-1.0f)/3.0f)-(-1.0f/3.0f));
+ *Z=(*X*(((52.0f*(100.0f*L)/((354.0f*u-134.0f)+13.0f*(100.0f*L)*(4.0f*D65X/
+ (D65X+15.0f*D65Y+3.0f*D65Z))))-1.0f)/3.0f))-5.0f*(*Y);
+}
+
static inline void ConvertRGBToXYZ(const double red,const double green,
const double blue,double *X,double *Y,double *Z)
{
*b=(200.0f*(y-z))/255.0f+0.5f;
}
+static inline void ConvertXYZToLuv(const double X,const double Y,const double Z,
+ double *L,double *u,double *v)
+{
+ double
+ alpha;
+
+ assert(L != (double *) NULL);
+ assert(u != (double *) NULL);
+ assert(v != (double *) NULL);
+ if ((Y/D65Y) > CIEEpsilon)
+ *L=(double) (116.0f*pow(Y/D65Y,1.0/3.0)-16.0f);
+ else
+ *L=CIEK*(Y/D65Y);
+ alpha=PerceptibleReciprocal(X+15.0f*Y+3.0f*Z);
+ *u=13.0f*(*L)*((4.0f*alpha*X)-(4.0f*D65X/(D65X+15.0f*D65Y+3.0f*D65Z)));
+ *v=13.0f*(*L)*((9.0f*alpha*Y)-(9.0f*D65Y/(D65X+15.0f*D65Y+3.0f*D65Z)));
+ *L/=100.0f;
+ *u=(*u+134.0f)/354.0f;
+ *v=(*v+140.0f)/262.0f;
+}
+
static inline void ConvertXYZToRGB(const double x,const double y,const double z,
double *red,double *green,double *blue)
{
% %
% %
% %
-% C o n v e r t L C H T o R G B %
+% C o n v e r t L C H a b T o R G B %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% ConvertLCHToRGB() transforms a (luma, chroma, hue) to a (red, green,
+% ConvertLCHabToRGB() transforms a (luma, chroma, hue) to a (red, green,
% blue) triple.
%
-% The format of the ConvertLCHToRGBImage method is:
+% The format of the ConvertLCHabToRGBImage method is:
%
-% void ConvertLCHToRGB(const double luma,const double chroma,
+% void ConvertLCHabToRGB(const double luma,const double chroma,
% const double hue,double *red,double *green,double *blue)
%
% A description of each parameter follows:
%
-% o luma, chroma, hue: A double value representing a
-% component of the LCH color space.
+% o luma, chroma, hue: A double value representing a component of the
+% LCHab color space.
%
% o red, green, blue: A pointer to a pixel component of type Quantum.
%
*/
-MagickPrivate void ConvertLCHToRGB(const double luma,const double chroma,
+MagickPrivate void ConvertLCHabToRGB(const double luma,const double chroma,
const double hue,double *red,double *green,double *blue)
{
double
Z;
/*
- Convert LCH to RGB colorspace.
+ Convert LCHab to RGB colorspace.
*/
assert(red != (double *) NULL);
assert(green != (double *) NULL);
% %
% %
% %
+% C o n v e r t L C H u v T o R G B %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ConvertLCHuvToRGB() transforms a (luma, chroma, hue) to a (red, green,
+% blue) triple.
+%
+% The format of the ConvertLCHuvToRGBImage method is:
+%
+% void ConvertLCHuvToRGB(const double luma,const double chroma,
+% const double hue,double *red,double *green,double *blue)
+%
+% A description of each parameter follows:
+%
+% o luma, chroma, hue: A double value representing a component of the
+% LCHuv color space.
+%
+% o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+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;
+
+ /*
+ Convert LCHuv to RGB colorspace.
+ */
+ 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,v,&X,&Y,&Z);
+ ConvertXYZToRGB(X,Y,Z,red,green,blue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
% C o n v e r t R G B T o H C L %
% %
% %
% %
% %
% %
-% C o n v e r t R G B T o L C H %
+% C o n v e r t R G B a b T o L C H %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% ConvertRGBToLCH() transforms a (red, green, blue) to a (luma, chroma,
+% ConvertRGBToLCHab() transforms a (red, green, blue) to a (luma, chroma,
% hue) triple.
%
-% The format of the ConvertRGBToLCH method is:
+% The format of the ConvertRGBToLCHab method is:
%
-% void ConvertRGBToLCH(const double red,const double green,
+% void ConvertRGBToLCHab(const double red,const double green,
% const double blue,double *luma,double *chroma,double *hue)
%
% A description of each parameter follows:
% component of the LCH color space.
%
*/
-MagickPrivate void ConvertRGBToLCH(const double red,const double green,
+MagickPrivate void ConvertRGBToLCHab(const double red,const double green,
const double blue,double *luma,double *chroma,double *hue)
{
double
% %
% %
% %
+% C o n v e r t R G B u v T o L C H %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ConvertRGBToLCHuv() transforms a (red, green, blue) to a (luma, chroma,
+% hue) triple.
+%
+% The format of the ConvertRGBToLCHuv method is:
+%
+% void ConvertRGBToLCHuv(const double red,const double green,
+% const double blue,double *luma,double *chroma,double *hue)
+%
+% A description of each parameter follows:
+%
+% o red, green, blue: A Quantum value representing the red, green, and
+% blue component of a pixel.
+%
+% o luma, chroma, hue: A pointer to a double value representing a
+% component of the LCHuv color space.
+%
+*/
+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;
+
+ /*
+ Convert RGB to LCH colorspace.
+ */
+ assert(luma != (double *) NULL);
+ assert(chroma != (double *) NULL);
+ assert(hue != (double *) NULL);
+ ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
+ ConvertXYZToLuv(X,Y,Z,&L,&u,&v);
+ C=hypot(u,v);
+ H=180.0*atan2(v,u)/MagickPI/360.0;
+ if (H < 0.0)
+ H+=1.0;
+ if (H >= 1.0)
+ H-=1.0;
+ *luma=L;
+ *chroma=C;
+ *hue=H;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
% E x p a n d A f f i n e %
% %
% %
{ "HWB", HWBColorspace, UndefinedOptionFlag, MagickFalse },
{ "Lab", LabColorspace, UndefinedOptionFlag, MagickFalse },
{ "LCH", LCHColorspace, UndefinedOptionFlag, MagickFalse },
+ { "LCHab", LCHabColorspace, UndefinedOptionFlag, MagickFalse },
+ { "LCHuv", LCHuvColorspace, UndefinedOptionFlag, MagickFalse },
{ "LMS", LMSColorspace, UndefinedOptionFlag, MagickFalse },
{ "Log", LogColorspace, UndefinedOptionFlag, MagickFalse },
{ "Luv", LuvColorspace, UndefinedOptionFlag, MagickFalse },