kis_color_conversions.cpp
1/*
2 * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#include <cmath>
20
21#include <tqglobal.h>
22
23#include "kis_color_conversions.h"
24
29void rgb_to_hsv(int R, int G, int B, int *H, int *S, int *V)
30{
31 unsigned int max = R;
32 unsigned int min = R;
33 unsigned char maxValue = 0; // r = 0, g = 1, b = 2
34
35 // find maximum and minimum RGB values
36 if(static_cast<unsigned int>(G) > max) {
37 max = G;
38 maxValue = 1;
39 }
40
41 if (static_cast<unsigned int>(B) > max)
42 {
43 max = B;
44 maxValue = 2;
45 }
46
47 if(static_cast<unsigned int>(G) < min)
48 min = G;
49
50 if(static_cast<unsigned int>(B) < min )
51 min = B;
52
53 int delta = max - min;
54
55 // To prevent division by zero later on.
56 if (delta == 0) delta = 1;
57
58 *V = max; // value
59 *S = max ? (510 * delta + max) / ( 2 * max) : 0; // saturation
60
61 // calc hue
62 if(*S == 0)
63 *H = -1; // undefined hue
64 else
65 {
66 switch(maxValue)
67 {
68 case 0: // red
69 if(G >= B)
70 *H = (120 * (G - B) + delta) / (2 * delta);
71 else
72 *H = (120 * (G - B + delta) + delta) / (2 * delta) + 300;
73 break;
74 case 1: // green
75 if(B > R)
76 *H = 120 + (120 * (B - R) + delta) / (2 * delta);
77 else
78 *H = 60 + (120 * (B - R + delta) + delta) / (2 * delta);
79 break;
80 case 2: // blue
81 if(R > G)
82 *H = 240 + (120 * (R - G) + delta) / (2 * delta);
83 else
84 *H = 180 + (120 * (R - G + delta) + delta) / (2 * delta);
85 break;
86 }
87 }
88}
89
90void hsv_to_rgb(int H, int S, int V, int *R, int *G, int *B)
91{
92 *R = *G = *B = V;
93
94 if (S != 0 && H != -1) { // chromatic
95
96 if (H >= 360) {
97 // angle > 360
98 H %= 360;
99 }
100
101 unsigned int f = H % 60;
102 H /= 60;
103 unsigned int p = static_cast<unsigned int>(2*V*(255-S)+255)/510;
104 unsigned int q, t;
105
106 if (H & 1) {
107 q = static_cast<unsigned int>(2 * V * (15300 - S * f) + 15300) / 30600;
108 switch (H) {
109 case 1:
110 *R = static_cast<int>(q);
111 *G = static_cast<int>(V);
112 *B = static_cast<int>(p);
113 break;
114 case 3:
115 *R = static_cast<int>(p);
116 *G = static_cast<int>(q);
117 *B = static_cast<int>(V);
118 break;
119 case 5:
120 *R = static_cast<int>(V);
121 *G = static_cast<int>(p);
122 *B = static_cast<int>(q);
123 break;
124 }
125 } else {
126 t = static_cast<unsigned int>(2 * V * (15300 - (S * (60 - f))) + 15300) / 30600;
127 switch (H) {
128 case 0:
129 *R = static_cast<int>(V);
130 *G = static_cast<int>(t);
131 *B = static_cast<int>(p);
132 break;
133 case 2:
134 *R = static_cast<int>(p);
135 *G = static_cast<int>(V);
136 *B = static_cast<int>(t);
137 break;
138 case 4:
139 *R = static_cast<int>(t);
140 *G = static_cast<int>(p);
141 *B = static_cast<int>(V);
142 break;
143 }
144 }
145 }
146}
147
148#define EPSILON 1e-6
149#define UNDEFINED_HUE -1
150
151void RGBToHSV(float r, float g, float b, float *h, float *s, float *v)
152{
153 float max = TQMAX(r, TQMAX(g, b));
154 float min = TQMIN(r, TQMIN(g, b));
155
156 *v = max;
157
158 if (max > EPSILON) {
159 *s = (max - min) / max;
160 } else {
161 *s = 0;
162 }
163
164 if (*s < EPSILON) {
165 *h = UNDEFINED_HUE;
166 } else {
167 float delta = max - min;
168
169 if (r == max) {
170 *h = (g - b) / delta;
171 } else if (g == max) {
172 *h = 2 + (b - r) / delta;
173 } else {
174 *h = 4 + (r - g) / delta;
175 }
176
177 *h *= 60;
178 if (*h < 0) {
179 *h += 360;
180 }
181 }
182}
183
184void HSVToRGB(float h, float s, float v, float *r, float *g, float *b)
185{
186 if (s < EPSILON || h == UNDEFINED_HUE) {
187 // Achromatic case
188
189 *r = v;
190 *g = v;
191 *b = v;
192 } else {
193 float f, p, q, t;
194 int i;
195
196 if (h > 360 - EPSILON) {
197 h -= 360;
198 }
199
200 h /= 60;
201 i = static_cast<int>(floor(h));
202 f = h - i;
203 p = v * (1 - s);
204 q = v * (1 - (s * f));
205 t = v * (1 - (s * (1 - f)));
206
207 switch (i) {
208 case 0:
209 *r = v;
210 *g = t;
211 *b = p;
212 break;
213 case 1:
214 *r = q;
215 *g = v;
216 *b = p;
217 break;
218 case 2:
219 *r = p;
220 *g = v;
221 *b = t;
222 break;
223 case 3:
224 *r = p;
225 *g = q;
226 *b = v;
227 break;
228 case 4:
229 *r = t;
230 *g = p;
231 *b = v;
232 break;
233 case 5:
234 *r = v;
235 *g = p;
236 *b = q;
237 break;
238 }
239 }
240}
241
242void rgb_to_hls(TQ_UINT8 red, TQ_UINT8 green, TQ_UINT8 blue, float * hue, float * lightness, float * saturation)
243{
244 float r = red / 255.0;
245 float g = green / 255.0;
246 float b = blue / 255.0;
247 float h = 0;
248 float l = 0;
249 float s = 0;
250
251 float max, min, delta;
252
253 max = TQMAX(r, g);
254 max = TQMAX(max, b);
255
256 min = TQMIN(r, g);
257 min = TQMIN(min, b);
258
259 delta = max - min;
260
261 l = (max + min) / 2;
262
263 if (delta == 0) {
264 // This is a gray, no chroma...
265 h = 0;
266 s = 0;
267 }
268 else {
269 if ( l < 0.5)
270 s = delta / ( max + min );
271 else
272 s = delta / ( 2 - max - min );
273
274 float delta_r, delta_g, delta_b;
275
276 delta_r = (( max - r ) / 6 ) / delta;
277 delta_g = (( max - g ) / 6 ) / delta;
278 delta_b = (( max - b ) / 6 ) / delta;
279
280 if ( r == max )
281 h = delta_b - delta_g;
282 else if ( g == max)
283 h = ( 1.0 / 3 ) + delta_r - delta_b;
284 else if ( b == max)
285 h = ( 2.0 / 3 ) + delta_g - delta_r;
286
287 if (h < 0) h += 1;
288 if (h > 1) h += 1;
289
290 }
291
292 *hue = h * 360;
293 *saturation = s;
294 *lightness = l;
295}
296
297float hue_value(float n1, float n2, float hue)
298{
299 if (hue > 360 )
300 hue = hue -360;
301 else if (hue < 0 )
302 hue = hue +360;
303 if (hue < 60 )
304 return n1 + (((n2 - n1) * hue) / 60);
305 else if (hue < 180 )
306 return n2;
307 else if (hue < 240 )
308 return n1 + (((n2 - n1) * (240 - hue)) / 60);
309 else return n1;
310}
311
312
313void hls_to_rgb(float h, float l, float s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b)
314{
315 float m1, m2;
316
317 if (l <= 0.5 )
318 m2 = l * ( 1 + s );
319 else
320 m2 = l + s - l * s;
321
322 m1 = 2 * l - m2;
323
324 *r = (TQ_UINT8)(hue_value(m1, m2, h + 120) * 255 + 0.5);
325 *g = (TQ_UINT8)(hue_value(m1, m2, h) * 255 + 0.5);
326 *b = (TQ_UINT8)(hue_value(m1, m2, h - 120) * 255 + 0.5);
327
328}
329
330void rgb_to_hls(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b, int * h, int * l, int * s)
331{
332 float hue, saturation, lightness;
333
334 rgb_to_hls(r, g, b, &hue, &lightness, &saturation);
335 *h = (int)(hue + 0.5);
336 *l = (int)(lightness * 255 + 0.5);
337 *s = (int)(saturation * 255 + 0.5);
338}
339
340void hls_to_rgb(int h, int l, int s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b)
341{
342 float hue = h;
343 float lightness = l / 255.0;
344 float saturation = s / 255.0;
345
346 hls_to_rgb(hue, lightness, saturation, r, g, b);
347}
348
349/*
350A Fast HSL-to-RGB Transform
351by Ken Fishkin
352from "Graphics Gems", Academic Press, 1990
353*/
354
355void RGBToHSL(float r, float g, float b, float *h, float *s, float *l)
356{
357 float v;
358 float m;
359 float vm;
360 float r2, g2, b2;
361
362 v = TQMAX(r,g);
363 v = TQMAX(v,b);
364 m = TQMIN(r,g);
365 m = TQMIN(m,b);
366
367 if ((*l = (m + v) / 2.0) <= 0.0) {
368 *h = UNDEFINED_HUE;
369 *s = 0;
370 return;
371 }
372 if ((*s = vm = v - m) > 0.0) {
373 *s /= (*l <= 0.5) ? (v + m ) :
374 (2.0 - v - m) ;
375 } else {
376 *h = UNDEFINED_HUE;
377 return;
378 }
379
380
381 r2 = (v - r) / vm;
382 g2 = (v - g) / vm;
383 b2 = (v - b) / vm;
384
385 if (r == v)
386 *h = (g == m ? 5.0 + b2 : 1.0 - g2);
387 else if (g == v)
388 *h = (b == m ? 1.0 + r2 : 3.0 - b2);
389 else
390 *h = (r == m ? 3.0 + g2 : 5.0 - r2);
391
392 *h *= 60;
393}
394
395void HSLToRGB(float h, float sl, float l, float *r, float *g, float *b)
396
397{
398 float v;
399
400 v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
401 if (v <= 0) {
402 *r = *g = *b = 0.0;
403 } else {
404 float m;
405 float sv;
406 int sextant;
407 float fract, vsf, mid1, mid2;
408
409 m = l + l - v;
410 sv = (v - m ) / v;
411 h /= 60.0;
412 sextant = static_cast<int>(h);
413 fract = h - sextant;
414 vsf = v * sv * fract;
415 mid1 = m + vsf;
416 mid2 = v - vsf;
417 switch (sextant) {
418 case 0: *r = v; *g = mid1; *b = m; break;
419 case 1: *r = mid2; *g = v; *b = m; break;
420 case 2: *r = m; *g = v; *b = mid1; break;
421 case 3: *r = m; *g = mid2; *b = v; break;
422 case 4: *r = mid1; *g = m; *b = v; break;
423 case 5: *r = v; *g = m; *b = mid2; break;
424 }
425 }
426}
427