xref: /haiku/src/add-ons/translators/wonderbrush/support/lab_convert.cpp (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
1 /*
2  * Copyright 2006, Haiku. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 #include <math.h>
10 #include <stdio.h>
11 
12 #include "support.h"
13 
14 #include "lab_convert.h"
15 
16 #define GAMMA_ZERO_ENTRIES 256
17 #define GAMMA_ENTRIES 10240
18 #define GAMMA_MAX_ENTRIES 256
19 #define GAMMA_TOTAL_ENTRIES GAMMA_ZERO_ENTRIES + GAMMA_ENTRIES + GAMMA_MAX_ENTRIES
20 
21 // init_gamma_table
22 uint8*
23 init_gamma_table()
24 {
25 	uint8* table = new uint8[GAMMA_TOTAL_ENTRIES];
26 	for (int32 i = 0; i < GAMMA_ZERO_ENTRIES; i++)
27 		table[i] = 0;
28 	for (int32 i = 0; i < GAMMA_ENTRIES; i++)
29 		table[i + GAMMA_ZERO_ENTRIES] = (uint8)(pow((float)i / (float)(GAMMA_ENTRIES - 1), 0.4) * 255.0 + 0.5);
30 	for (int32 i = 0; i < GAMMA_MAX_ENTRIES; i++)
31 		table[i + GAMMA_ZERO_ENTRIES + GAMMA_ENTRIES] = 255;
32 	return table;
33 }
34 
35 // init_linear_table
36 float*
37 init_linear_table()
38 {
39 	float* table = new float[256];
40 	for (int32 i = 0; i < 256; i++)
41 		table[i] = pow((float)i / 255.0, 2.5);
42 	return table;
43 }
44 
45 // conversion from RGB (0...255) to linear and normalized RGB (0...1)
46 /*static uint8* gammaTable = init_gamma_table();*/
47 static float* linearTable = init_linear_table();
48 
49 // matrix entries: XYZ -> RGB (709 RGB, D65 Whitepoint)
50 /*const float Rx = 3.240479;
51 const float Ry = -1.537150;
52 const float Rz = -0.498535;
53 const float Gx = -0.969256;
54 const float Gy = 1.875992;
55 const float Gz = 0.041556;
56 const float Bx = 0.055648;
57 const float By = -0.204043;
58 const float Bz = 1.057311;*/
59 
60 // matrix entries: XYZ -> sRGB (D65 Whitepoint)
61 const float Rx = 3.24071;
62 const float Ry = -1.53726;
63 const float Rz = -0.498571;
64 const float Gx = -0.969258;
65 const float Gy = 1.87599;
66 const float Gz = 0.0415557;
67 const float Bx = 0.0556352;
68 const float By = -0.203996;
69 const float Bz = 1.05707;
70 
71 
72 // matrix entries scaled: XYZ(0...1) -> RGB(0...255)
73 const float RX = Rx * 255;
74 const float RY = Ry * 255;
75 const float RZ = Rz * 255;
76 const float GX = Gx * 255;
77 const float GY = Gy * 255;
78 const float GZ = Gz * 255;
79 const float BX = Bx * 255;
80 const float BY = By * 255;
81 const float BZ = Bz * 255;
82 
83 // matrix etries: RGB -> XYZ
84 /*const float Xr = 0.412453;
85 const float Xg = 0.357580;
86 const float Xb = 0.189423;
87 const float Yr = 0.212671;
88 const float Yg = 0.715160;
89 const float Yb = 0.072169;
90 const float Zr = 0.019334;
91 const float Zg = 0.119193;
92 const float Zb = 0.950227;*/
93 
94 // matrix etries: sRGB -> XYZ (D65 Whitepoint)
95 const float Xr = 0.412424;
96 const float Xg = 0.357579;
97 const float Xb = 0.180464;
98 const float Yr = 0.212656;
99 const float Yg = 0.715158;
100 const float Yb = 0.0721856;
101 const float Zr = 0.0193324;
102 const float Zg = 0.119193;
103 const float Zb = 0.950444;
104 
105 // matrix entries scaled: RGB(0...255) -> XYZ(0...1)
106 const float XR = Xr / 255;
107 const float XG = Xg / 255;
108 const float XB = Xb / 255;
109 const float YR = Yr / 255;
110 const float YG = Yg / 255;
111 const float YB = Yb / 255;
112 const float ZR = Zr / 255;
113 const float ZG = Zg / 255;
114 const float ZB = Zb / 255;
115 
116 // white point
117 const float Xn = Xr + Xg + Xb;
118 const float Yn = Yr + Yg + Yb;
119 const float Zn = Zr + Zg + Zb;
120 
121 // matrix entries scaled and white point normalized: RGB(0...255) -> XYZ(0...1/WP)
122 const float XRn = Xr / Xn;
123 const float XGn = Xg / Xn;
124 const float XBn = Xb / Xn;
125 const float YRn = Yr / Yn;
126 const float YGn = Yg / Yn;
127 const float YBn = Yb / Yn;
128 const float ZRn = Zr / Zn;
129 const float ZGn = Zg / Zn;
130 const float ZBn = Zb / Zn;
131 
132 // lab2rgb
133 void
134 lab2rgb(float L, float a, float b, uint8& R, uint8& G, uint8& B)
135 {
136 	float P = (L + 16) / 116;
137 	float Pa500 = P + a / 500;
138 	float Pb200 = P - b / 200;
139 	float X = Xn * Pa500 * Pa500 * Pa500;
140 	float Y = Yn * P * P * P;
141 	float Z = Zn * Pb200 * Pb200 * Pb200;
142 /*	float linearR = max_c(0.0, min_c(1.0, Rx * X + Ry * Y + Rz * Z));
143 	float linearG = max_c(0.0, min_c(1.0, Gx * X + Gy * Y + Gz * Z));
144 	float linearB = max_c(0.0, min_c(1.0, Bx * X + By * Y + Bz * Z));
145 	R = (uint8)(pow(linearR, 0.4) * 255.0 + 0.5);
146 	G = (uint8)(pow(linearG, 0.4) * 255.0 + 0.5);
147 	B = (uint8)(pow(linearB, 0.4) * 255.0 + 0.5);*/
148 	float linearR = Rx * X + Ry * Y + Rz * Z;
149 	float linearG = Gx * X + Gy * Y + Gz * Z;
150 	float linearB = Bx * X + By * Y + Bz * Z;
151 	R = (uint8)constrain_int32_0_255((int32)(pow(linearR, 0.4) * 255.0 + 0.5));
152 	G = (uint8)constrain_int32_0_255((int32)(pow(linearG, 0.4) * 255.0 + 0.5));
153 	B = (uint8)constrain_int32_0_255((int32)(pow(linearB, 0.4) * 255.0 + 0.5));
154 /*	float linearR = Rx * X + Ry * Y + Rz * Z;
155 	float linearG = Gx * X + Gy * Y + Gz * Z;
156 	float linearB = Bx * X + By * Y + Bz * Z;
157 	R = gammaTable[(uint32)(linearR * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];
158 	G = gammaTable[(uint32)(linearG * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];
159 	B = gammaTable[(uint32)(linearB * (GAMMA_ENTRIES - 1) + 0.5) + GAMMA_ZERO_ENTRIES];*/
160 }
161 
162 inline float
163 f(float t)
164 {
165 	if (t > 0.008856)
166 		return pow(t, 1.0 / 3.0);
167 	return 7.787 * t + 16.0 / 116;
168 }
169 
170 // rgb2lab
171 void
172 rgb2lab(uint8 R, uint8 G, uint8 B, float& L, float& a, float& b)
173 {
174 /*	float linearR = pow((float)R / 255.0, 2.5);
175 	float linearG = pow((float)G / 255.0, 2.5);
176 	float linearB = pow((float)B / 255.0, 2.5);*/
177 	float linearR = linearTable[R];
178 	float linearG = linearTable[G];
179 	float linearB = linearTable[B];
180 	float Xq = XRn * linearR + XGn * linearG + XBn * linearB; // == X/Xn
181 	float Yq = YRn * linearR + YGn * linearG + YBn * linearB; // == Y/Yn
182 	float Zq = ZRn * linearR + ZGn * linearG + ZBn * linearB; // == Z/Zn
183 	if (Yq > 0.008856)
184 		L = 116.0 * pow(Yq, 1.0 / 3.0) - 16;
185 	else
186 		L = 903.3 * Yq;
187 	a = 500 * (f(Xq) - f(Yq));
188 	b = 200 * (f(Yq) - f(Zq));
189 }
190 
191 // replace_luminance
192 void
193 replace_luminance(uint8& r1, uint8& g1, uint8& b1, uint8 r2, uint8 g2, uint8 b2)
194 {
195 	float CIEL1, CIEa1, CIEb1, CIEL2;//, CIEa2, CIEb2;
196 	rgb2lab(r1, g1, b1, CIEL1, CIEa1, CIEb1);
197 //	rgb2lab(r2, g2, b2, CIEL2, CIEa2, CIEb2);
198 	CIEL2 = ((linearTable[r2] + linearTable[g2] + linearTable[b2]) / 3.0) * 100.0;
199 	lab2rgb(CIEL2, CIEa1, CIEb1, r1, g1, b1);
200 }
201