xref: /haiku/src/add-ons/translators/wonderbrush/support/lab_convert.cpp (revision 9e72a18d0fd94acd2384b75b30a3ede6fad2af1c)
173a2ffbaSStephan Aßmus /*
273a2ffbaSStephan Aßmus  * Copyright 2006, Haiku. All rights reserved.
373a2ffbaSStephan Aßmus  * Distributed under the terms of the MIT License.
473a2ffbaSStephan Aßmus  *
573a2ffbaSStephan Aßmus  * Authors:
673a2ffbaSStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
773a2ffbaSStephan Aßmus  */
873a2ffbaSStephan Aßmus 
973a2ffbaSStephan Aßmus #include <math.h>
1073a2ffbaSStephan Aßmus #include <stdio.h>
1173a2ffbaSStephan Aßmus 
1273a2ffbaSStephan Aßmus #include "support.h"
1373a2ffbaSStephan Aßmus 
1473a2ffbaSStephan Aßmus #include "lab_convert.h"
1573a2ffbaSStephan Aßmus 
1673a2ffbaSStephan Aßmus #define GAMMA_ZERO_ENTRIES 256
1773a2ffbaSStephan Aßmus #define GAMMA_ENTRIES 10240
1873a2ffbaSStephan Aßmus #define GAMMA_MAX_ENTRIES 256
1973a2ffbaSStephan Aßmus #define GAMMA_TOTAL_ENTRIES GAMMA_ZERO_ENTRIES + GAMMA_ENTRIES + GAMMA_MAX_ENTRIES
2073a2ffbaSStephan Aßmus 
2173a2ffbaSStephan Aßmus // init_gamma_table
2273a2ffbaSStephan Aßmus uint8*
init_gamma_table()2373a2ffbaSStephan Aßmus init_gamma_table()
2473a2ffbaSStephan Aßmus {
2573a2ffbaSStephan Aßmus 	uint8* table = new uint8[GAMMA_TOTAL_ENTRIES];
2673a2ffbaSStephan Aßmus 	for (int32 i = 0; i < GAMMA_ZERO_ENTRIES; i++)
2773a2ffbaSStephan Aßmus 		table[i] = 0;
2873a2ffbaSStephan Aßmus 	for (int32 i = 0; i < GAMMA_ENTRIES; i++)
2973a2ffbaSStephan Aßmus 		table[i + GAMMA_ZERO_ENTRIES] = (uint8)(pow((float)i / (float)(GAMMA_ENTRIES - 1), 0.4) * 255.0 + 0.5);
3073a2ffbaSStephan Aßmus 	for (int32 i = 0; i < GAMMA_MAX_ENTRIES; i++)
3173a2ffbaSStephan Aßmus 		table[i + GAMMA_ZERO_ENTRIES + GAMMA_ENTRIES] = 255;
3273a2ffbaSStephan Aßmus 	return table;
3373a2ffbaSStephan Aßmus }
3473a2ffbaSStephan Aßmus 
3573a2ffbaSStephan Aßmus // init_linear_table
3673a2ffbaSStephan Aßmus float*
init_linear_table()3773a2ffbaSStephan Aßmus init_linear_table()
3873a2ffbaSStephan Aßmus {
3973a2ffbaSStephan Aßmus 	float* table = new float[256];
4073a2ffbaSStephan Aßmus 	for (int32 i = 0; i < 256; i++)
4173a2ffbaSStephan Aßmus 		table[i] = pow((float)i / 255.0, 2.5);
4273a2ffbaSStephan Aßmus 	return table;
4373a2ffbaSStephan Aßmus }
4473a2ffbaSStephan Aßmus 
4573a2ffbaSStephan Aßmus // conversion from RGB (0...255) to linear and normalized RGB (0...1)
46*9e72a18dSAdrien Destugues /*static uint8* gammaTable = init_gamma_table();*/
4773a2ffbaSStephan Aßmus static float* linearTable = init_linear_table();
4873a2ffbaSStephan Aßmus 
4973a2ffbaSStephan Aßmus // matrix entries: XYZ -> RGB (709 RGB, D65 Whitepoint)
5073a2ffbaSStephan Aßmus /*const float Rx = 3.240479;
5173a2ffbaSStephan Aßmus const float Ry = -1.537150;
5273a2ffbaSStephan Aßmus const float Rz = -0.498535;
5373a2ffbaSStephan Aßmus const float Gx = -0.969256;
5473a2ffbaSStephan Aßmus const float Gy = 1.875992;
5573a2ffbaSStephan Aßmus const float Gz = 0.041556;
5673a2ffbaSStephan Aßmus const float Bx = 0.055648;
5773a2ffbaSStephan Aßmus const float By = -0.204043;
5873a2ffbaSStephan Aßmus const float Bz = 1.057311;*/
5973a2ffbaSStephan Aßmus 
6073a2ffbaSStephan Aßmus // matrix entries: XYZ -> sRGB (D65 Whitepoint)
6173a2ffbaSStephan Aßmus const float Rx = 3.24071;
6273a2ffbaSStephan Aßmus const float Ry = -1.53726;
6373a2ffbaSStephan Aßmus const float Rz = -0.498571;
6473a2ffbaSStephan Aßmus const float Gx = -0.969258;
6573a2ffbaSStephan Aßmus const float Gy = 1.87599;
6673a2ffbaSStephan Aßmus const float Gz = 0.0415557;
6773a2ffbaSStephan Aßmus const float Bx = 0.0556352;
6873a2ffbaSStephan Aßmus const float By = -0.203996;
6973a2ffbaSStephan Aßmus const float Bz = 1.05707;
7073a2ffbaSStephan Aßmus 
7173a2ffbaSStephan Aßmus 
7273a2ffbaSStephan Aßmus // matrix entries scaled: XYZ(0...1) -> RGB(0...255)
7373a2ffbaSStephan Aßmus const float RX = Rx * 255;
7473a2ffbaSStephan Aßmus const float RY = Ry * 255;
7573a2ffbaSStephan Aßmus const float RZ = Rz * 255;
7673a2ffbaSStephan Aßmus const float GX = Gx * 255;
7773a2ffbaSStephan Aßmus const float GY = Gy * 255;
7873a2ffbaSStephan Aßmus const float GZ = Gz * 255;
7973a2ffbaSStephan Aßmus const float BX = Bx * 255;
8073a2ffbaSStephan Aßmus const float BY = By * 255;
8173a2ffbaSStephan Aßmus const float BZ = Bz * 255;
8273a2ffbaSStephan Aßmus 
8373a2ffbaSStephan Aßmus // matrix etries: RGB -> XYZ
8473a2ffbaSStephan Aßmus /*const float Xr = 0.412453;
8573a2ffbaSStephan Aßmus const float Xg = 0.357580;
8673a2ffbaSStephan Aßmus const float Xb = 0.189423;
8773a2ffbaSStephan Aßmus const float Yr = 0.212671;
8873a2ffbaSStephan Aßmus const float Yg = 0.715160;
8973a2ffbaSStephan Aßmus const float Yb = 0.072169;
9073a2ffbaSStephan Aßmus const float Zr = 0.019334;
9173a2ffbaSStephan Aßmus const float Zg = 0.119193;
9273a2ffbaSStephan Aßmus const float Zb = 0.950227;*/
9373a2ffbaSStephan Aßmus 
9473a2ffbaSStephan Aßmus // matrix etries: sRGB -> XYZ (D65 Whitepoint)
9573a2ffbaSStephan Aßmus const float Xr = 0.412424;
9673a2ffbaSStephan Aßmus const float Xg = 0.357579;
9773a2ffbaSStephan Aßmus const float Xb = 0.180464;
9873a2ffbaSStephan Aßmus const float Yr = 0.212656;
9973a2ffbaSStephan Aßmus const float Yg = 0.715158;
10073a2ffbaSStephan Aßmus const float Yb = 0.0721856;
10173a2ffbaSStephan Aßmus const float Zr = 0.0193324;
10273a2ffbaSStephan Aßmus const float Zg = 0.119193;
10373a2ffbaSStephan Aßmus const float Zb = 0.950444;
10473a2ffbaSStephan Aßmus 
10573a2ffbaSStephan Aßmus // matrix entries scaled: RGB(0...255) -> XYZ(0...1)
10673a2ffbaSStephan Aßmus const float XR = Xr / 255;
10773a2ffbaSStephan Aßmus const float XG = Xg / 255;
10873a2ffbaSStephan Aßmus const float XB = Xb / 255;
10973a2ffbaSStephan Aßmus const float YR = Yr / 255;
11073a2ffbaSStephan Aßmus const float YG = Yg / 255;
11173a2ffbaSStephan Aßmus const float YB = Yb / 255;
11273a2ffbaSStephan Aßmus const float ZR = Zr / 255;
11373a2ffbaSStephan Aßmus const float ZG = Zg / 255;
11473a2ffbaSStephan Aßmus const float ZB = Zb / 255;
11573a2ffbaSStephan Aßmus 
11673a2ffbaSStephan Aßmus // white point
11773a2ffbaSStephan Aßmus const float Xn = Xr + Xg + Xb;
11873a2ffbaSStephan Aßmus const float Yn = Yr + Yg + Yb;
11973a2ffbaSStephan Aßmus const float Zn = Zr + Zg + Zb;
12073a2ffbaSStephan Aßmus 
12173a2ffbaSStephan Aßmus // matrix entries scaled and white point normalized: RGB(0...255) -> XYZ(0...1/WP)
12273a2ffbaSStephan Aßmus const float XRn = Xr / Xn;
12373a2ffbaSStephan Aßmus const float XGn = Xg / Xn;
12473a2ffbaSStephan Aßmus const float XBn = Xb / Xn;
12573a2ffbaSStephan Aßmus const float YRn = Yr / Yn;
12673a2ffbaSStephan Aßmus const float YGn = Yg / Yn;
12773a2ffbaSStephan Aßmus const float YBn = Yb / Yn;
12873a2ffbaSStephan Aßmus const float ZRn = Zr / Zn;
12973a2ffbaSStephan Aßmus const float ZGn = Zg / Zn;
13073a2ffbaSStephan Aßmus const float ZBn = Zb / Zn;
13173a2ffbaSStephan Aßmus 
13273a2ffbaSStephan Aßmus // lab2rgb
13373a2ffbaSStephan Aßmus void
lab2rgb(float L,float a,float b,uint8 & R,uint8 & G,uint8 & B)13473a2ffbaSStephan Aßmus lab2rgb(float L, float a, float b, uint8& R, uint8& G, uint8& B)
13573a2ffbaSStephan Aßmus {
13673a2ffbaSStephan Aßmus 	float P = (L + 16) / 116;
13773a2ffbaSStephan Aßmus 	float Pa500 = P + a / 500;
13873a2ffbaSStephan Aßmus 	float Pb200 = P - b / 200;
13973a2ffbaSStephan Aßmus 	float X = Xn * Pa500 * Pa500 * Pa500;
14073a2ffbaSStephan Aßmus 	float Y = Yn * P * P * P;
14173a2ffbaSStephan Aßmus 	float Z = Zn * Pb200 * Pb200 * Pb200;
14273a2ffbaSStephan Aßmus /*	float linearR = max_c(0.0, min_c(1.0, Rx * X + Ry * Y + Rz * Z));
14373a2ffbaSStephan Aßmus 	float linearG = max_c(0.0, min_c(1.0, Gx * X + Gy * Y + Gz * Z));
14473a2ffbaSStephan Aßmus 	float linearB = max_c(0.0, min_c(1.0, Bx * X + By * Y + Bz * Z));
14573a2ffbaSStephan Aßmus 	R = (uint8)(pow(linearR, 0.4) * 255.0 + 0.5);
14673a2ffbaSStephan Aßmus 	G = (uint8)(pow(linearG, 0.4) * 255.0 + 0.5);
14773a2ffbaSStephan Aßmus 	B = (uint8)(pow(linearB, 0.4) * 255.0 + 0.5);*/
14873a2ffbaSStephan Aßmus 	float linearR = Rx * X + Ry * Y + Rz * Z;
14973a2ffbaSStephan Aßmus 	float linearG = Gx * X + Gy * Y + Gz * Z;
15073a2ffbaSStephan Aßmus 	float linearB = Bx * X + By * Y + Bz * Z;
15173a2ffbaSStephan Aßmus 	R = (uint8)constrain_int32_0_255((int32)(pow(linearR, 0.4) * 255.0 + 0.5));
15273a2ffbaSStephan Aßmus 	G = (uint8)constrain_int32_0_255((int32)(pow(linearG, 0.4) * 255.0 + 0.5));
15373a2ffbaSStephan Aßmus 	B = (uint8)constrain_int32_0_255((int32)(pow(linearB, 0.4) * 255.0 + 0.5));
15473a2ffbaSStephan Aßmus /*	float linearR = Rx * X + Ry * Y + Rz * Z;
15573a2ffbaSStephan Aßmus 	float linearG = Gx * X + Gy * Y + Gz * Z;
15673a2ffbaSStephan Aßmus 	float linearB = Bx * X + By * Y + Bz * Z;
15773a2ffbaSStephan Aßmus 	R = gammaTable[(uint32)(linearR * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];
15873a2ffbaSStephan Aßmus 	G = gammaTable[(uint32)(linearG * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];
15973a2ffbaSStephan Aßmus 	B = gammaTable[(uint32)(linearB * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];*/
16073a2ffbaSStephan Aßmus }
16173a2ffbaSStephan Aßmus 
16273a2ffbaSStephan Aßmus inline float
f(float t)16373a2ffbaSStephan Aßmus f(float t)
16473a2ffbaSStephan Aßmus {
16573a2ffbaSStephan Aßmus 	if (t > 0.008856)
16673a2ffbaSStephan Aßmus 		return pow(t, 1.0 / 3.0);
16773a2ffbaSStephan Aßmus 	return 7.787 * t + 16.0 / 116;
16873a2ffbaSStephan Aßmus }
16973a2ffbaSStephan Aßmus 
17073a2ffbaSStephan Aßmus // rgb2lab
17173a2ffbaSStephan Aßmus void
rgb2lab(uint8 R,uint8 G,uint8 B,float & L,float & a,float & b)17273a2ffbaSStephan Aßmus rgb2lab(uint8 R, uint8 G, uint8 B, float& L, float& a, float& b)
17373a2ffbaSStephan Aßmus {
17473a2ffbaSStephan Aßmus /*	float linearR = pow((float)R / 255.0, 2.5);
17573a2ffbaSStephan Aßmus 	float linearG = pow((float)G / 255.0, 2.5);
17673a2ffbaSStephan Aßmus 	float linearB = pow((float)B / 255.0, 2.5);*/
17773a2ffbaSStephan Aßmus 	float linearR = linearTable[R];
17873a2ffbaSStephan Aßmus 	float linearG = linearTable[G];
17973a2ffbaSStephan Aßmus 	float linearB = linearTable[B];
18073a2ffbaSStephan Aßmus 	float Xq = XRn * linearR + XGn * linearG + XBn * linearB; // == X/Xn
18173a2ffbaSStephan Aßmus 	float Yq = YRn * linearR + YGn * linearG + YBn * linearB; // == Y/Yn
18273a2ffbaSStephan Aßmus 	float Zq = ZRn * linearR + ZGn * linearG + ZBn * linearB; // == Z/Zn
18373a2ffbaSStephan Aßmus 	if (Yq > 0.008856)
18473a2ffbaSStephan Aßmus 		L = 116.0 * pow(Yq, 1.0 / 3.0) - 16;
18573a2ffbaSStephan Aßmus 	else
18673a2ffbaSStephan Aßmus 		L = 903.3 * Yq;
18773a2ffbaSStephan Aßmus 	a = 500 * (f(Xq) - f(Yq));
18873a2ffbaSStephan Aßmus 	b = 200 * (f(Yq) - f(Zq));
18973a2ffbaSStephan Aßmus }
19073a2ffbaSStephan Aßmus 
19173a2ffbaSStephan Aßmus // replace_luminance
19273a2ffbaSStephan Aßmus void
replace_luminance(uint8 & r1,uint8 & g1,uint8 & b1,uint8 r2,uint8 g2,uint8 b2)19373a2ffbaSStephan Aßmus replace_luminance(uint8& r1, uint8& g1, uint8& b1, uint8 r2, uint8 g2, uint8 b2)
19473a2ffbaSStephan Aßmus {
19573a2ffbaSStephan Aßmus 	float CIEL1, CIEa1, CIEb1, CIEL2;//, CIEa2, CIEb2;
19673a2ffbaSStephan Aßmus 	rgb2lab(r1, g1, b1, CIEL1, CIEa1, CIEb1);
19773a2ffbaSStephan Aßmus //	rgb2lab(r2, g2, b2, CIEL2, CIEa2, CIEb2);
19873a2ffbaSStephan Aßmus 	CIEL2 = ((linearTable[r2] + linearTable[g2] + linearTable[b2]) / 3.0) * 100.0;
19973a2ffbaSStephan Aßmus 	lab2rgb(CIEL2, CIEa1, CIEb1, r1, g1, b1);
20073a2ffbaSStephan Aßmus }
201