/*
From The website of Dr. Marcelo Gattass
http://www.tecgraf.puc-rio.br/~mgattass/color/
http://www.codefans.net
Color Conversion Routines
*/
#include "cc.h"
#include <assert.h>
#include <math.h>
/*
* Tristimulus reference values
*/
const double _ccTristimulusValues[ccNTristimulus][3] =
{
/* 2 degrees */
/*ccTA_2*/
{
109.850, 100.000, 35.585
}
, /*ccTC_2*/
{
98.074, 100.000, 118.232
}
, /* D50 */
{
96.422, 100.000, 82.521
}
, /* D55 */
{
95.682, 100.000, 92.149
}
, /* D65 */
{
95.047, 100.000, 108.883
}
, /* D75 */
{
94.972, 100.000, 122.638
}
, /* F2 */
{
99.187, 100.000, 67.395
}
, /* F7 */
{
95.044, 100.000, 108.755
}
, /* F11 */
{
100.966, 100.000, 64.370
}
,
/* 10 degrees */
/* A */
{
111.144, 100.000, 35.200
}
, /* C */
{
97.285, 100.000, 116.145
}
, /* D50 */
{
96.720, 100.000, 81.427
}
, /* D55 */
{
95.799, 100.000, 90.926
}
, /* D65 */
{
94.811, 100.000, 107.304
}
, /* D75 */
{
94.416, 100.000, 120.641
}
, /* F2 */
{
103.280, 100.000, 69.026
}
, /* F7 */
{
95.792, 100.000, 107.687
}
, /* F11 */
{
103.866, 100.000, 65.627
}
};
static double ccmin(double val1, double val2, double val3)
{
if (val1 < val2)
{
if (val1 < val3)
return val1;
else
return val3;
}
else if (val2 < val3)
return val2;
return val3;
}
static double ccmax(double val1, double val2, double val3)
{
if (val1 > val2)
{
if (val1 > val3)
return val1;
else
return val3;
}
else if (val2 > val3)
return val2;
return val3;
}
static double Hue_2_RGB(double v1, double v2, double vH)
{
if (vH < 0)
vH += 1;
if (vH > 1)
vH -= 1;
if ((6 *vH) < 1)
return (v1 + (v2 - v1) *6 * vH);
if ((2 *vH) < 1)
return (v2);
if ((3 *vH) < 2)
return (v1 + (v2 - v1)*((2. / 3) - vH) *6);
return (v1);
}
static double degree_2_radian(double val)
{
return (val *PI) / 180;
}
//RGB values = From 0 to 1
int RGBtoHSL(double r, double g, double b, double *h, double *s, double *l)
{
double vmin, vmax, delta;
double dr, dg, db;
vmin = ccmin(r, g, b); // Min. value of RGB
vmax = ccmax(r, g, b); // Max. value of RGB
delta = vmax - vmin; // Delta RGB value
*l = (vmax + vmin) / 2;
if (delta == 0)
// This is a gray, no chroma...
{
*h = 0; // HSL results = From 0 to 1
*s = 0;
}
else
// Chromatic data...
{
if (*l < 0.5)
*s = delta / (vmax + vmin);
else
*s = delta / (2-vmax - vmin);
dr = (((vmax - r) / 6.0) + (delta / 2.0)) / delta;
dg = (((vmax - g) / 6.0) + (delta / 2.0)) / delta;
db = (((vmax - b) / 6.0) + (delta / 2.0)) / delta;
if (r == vmax)
*h = db - dg;
else if (g == vmax)
*h = (1.0 / 3.0) + dr - db;
else if (b == vmax)
*h = (2.0 / 3.0) + dg - dr;
if (*h < 0)
*h += 1;
if (*h > 1)
*h -= 1;
}
return 1;
}
int HSLtoRGB(double h, double s, double l, double *r, double *g, double *b)
{
double v1, v2;
if (s == 0)
// HSL values = From 0 to 1
{
*r = l; // RGB results = From 0 to 1
*g = l;
*b = l;
}
else
{
if (l < 0.5)
v2 = l *(1+s);
else
v2 = (l + s) - (s *l);
v1 = 2 * l - v2;
*r = Hue_2_RGB(v1, v2, h + (1.0 / 3.0));
*g = Hue_2_RGB(v1, v2, h);
*b = Hue_2_RGB(v1, v2, h - (1.0 / 3.0));
}
return 1;
}
// RGB values = From 0 to 1
int fRGBtoCMY(double r, double g, double b, double *c, double *m, double *y)
{
assert(c && m && y);
*c = 1-r;
*m = 1-g;
*y = 1-b;
return 1;
}
// RGB values = From 0 to 255
int iRGBtoCMY(int r, int g, int b, double *c, double *m, double *y)
{
assert(c && m && y);
assert(r >= 0 && r < 256);
assert(g >= 0 && g < 256);
assert(b >= 0 && b < 256);
*c = 1-((double)r / 255);
*m = 1-((double)g / 255);
*y = 1-((double)b / 255);
return 1;
}
// CMY values = From 0 to 255
int CMYtofRGB(double c, double m, double y, double *r, double *g, double *b)
{
assert(r && g && b);
assert(c >= 0 && c <= 1);
assert(m >= 0 && m <= 1);
assert(y >= 0 && y <= 1);
*r = (1-c);
*g = (1-m);
*b = (1-y);
return 1;
}
// CMY values = From 0 to 1
int CMYtoiRGB(double c, double m, double y, int *r, int *g, int *b)
{
assert(r && g && b);
assert(c >= 0 && c <= 1);
assert(m >= 0 && m <= 1);
assert(y >= 0 && y <= 1);
*r = (int)(1-c) *255;
*g = (int)(1-m) *255;
*b = (int)(1-y) *255;
return 1;
}
// CMY values = From 0 to 1
int CMYtoCMYK(double c, double m, double y, double *C, double *M, double *Y, double *K)
{
double var_K = 1;
assert(C && M && Y && K);
assert(c >= 0 && c <= 1);
assert(m >= 0 && m <= 1);
assert(y >= 0 && y <= 1);
if (c < var_K)
var_K = c;
if (m < var_K)
var_K = m;
if (y < var_K)
var_K = y;
*C = (c - var_K) / (1-var_K);
*M = (m - var_K) / (1-var_K);
*Y = (y - var_K) / (1-var_K);
*K = var_K;
return 1;
}
// CMYK values = From 0 to 1
int CMYKtoCMY(double c, double m, double y, double k, double *C, double *M, double *Y)
{
assert(C && M && Y);
assert(c >= 0 && c <= 1);
assert(m >= 0 && m <= 1);
assert(y >= 0 && y <= 1);
assert(k >= 0 && k <= 1);
*C = (c *(1-k) + k);
*M = (m *(1-k) + k);
*Y = (y *(1-k) + k);
return 1;
}
int RGBtoHSV(double r, double g, double b, double *h, double *s, double *v)
{
double var_Min;
double var_Max;
double del_Max;
var_Min = ccmin(r, g, b); //Min. value of RGB
var_Max = ccmax(r, g, b); //Max. value of RGB
del_Max = var_Max - var_Min; //Delta RGB value
*v = var_Max;
if (del_Max == 0)
// This is a gray, no chroma...
{
*h = 0; // HSV results = From 0 to 1
*s = 0;
}
else
// Chromatic data...
{
double del_R = (((var_Max - r) / 6) + (del_Max / 2)) / del_Max;
double del_G = (((var_Max - g) / 6) + (del_Max / 2)) / del_Max;
double del_B = (((var_Max - b) / 6) + (del_Max / 2)) / del_Max;
*s = del_Max / var_Max;
if (r == var_Max)
*h = del_B - del_G;
else if (g == var_Max)
*h = (1. / 3) + del_R - del_B;
else if (b == var_Max)
*h = (2. / 3) + del_G - del_R;
if (*h < 0)
;
*h += 1;
if (*h > 1)
;
*h -= 1;
}
return 1;
}
int HSVtoRGB(double h, double s, double v, double *r, double *g, double *b)
{
if (s == 0)
// HSV values = From 0 to 1
{
*r = v;
*g = v;
*b = v;
}
else
{
double var_h = h * 6;
double var_i = floor(var_h);
double var_1 = v *(1-s);
double var_2 = v *(1-s *(var_h - var_i));
double var_3 = v *(1-s *(1-(var_h - var_i)));
if (var_i == 0)
{
*r = v;
*g = var_3;
*b = var_1;
}
else if (var_i == 1)
{