File indexing completed on 2024-05-12 15:59:31
0001 /* 0002 * SPDX-FileCopyrightText: 2005 Boudewijn Rempt <boud@valdyas.org> 0003 * SPDX-FileCopyrightText: 2014 Wolthera van Hövell <griffinvalley@gmail.com> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.1-or-later 0006 */ 0007 0008 #include "KoColorConversions.h" 0009 0010 #include <cmath> 0011 0012 #include <QtGlobal> 0013 0014 /** 0015 * A number of often-used conversions between color models 0016 */ 0017 0018 void rgb_to_hsv(int R, int G, int B, int *H, int *S, int *V) 0019 { 0020 unsigned int max = R; 0021 unsigned int min = R; 0022 unsigned char maxValue = 0; // r = 0, g = 1, b = 2 0023 0024 // find maximum and minimum RGB values 0025 if (static_cast<unsigned int>(G) > max) { 0026 max = G; 0027 maxValue = 1; 0028 } 0029 0030 if (static_cast<unsigned int>(B) > max) { 0031 max = B; 0032 maxValue = 2; 0033 } 0034 0035 if (static_cast<unsigned int>(G) < min) 0036 min = G; 0037 0038 if (static_cast<unsigned int>(B) < min) 0039 min = B; 0040 0041 int delta = max - min; 0042 *V = max; // value 0043 *S = max ? (510 * delta + max) / (2 * max) : 0; // saturation 0044 0045 // calc hue 0046 if (*S == 0) 0047 *H = -1; // undefined hue 0048 else { 0049 switch (maxValue) { 0050 case 0: // red 0051 if (G >= B) 0052 *H = (120 * (G - B) + delta) / (2 * delta); 0053 else 0054 *H = (120 * (G - B + delta) + delta) / (2 * delta) + 300; 0055 break; 0056 case 1: // green 0057 if (B > R) 0058 *H = 120 + (120 * (B - R) + delta) / (2 * delta); 0059 else 0060 *H = 60 + (120 * (B - R + delta) + delta) / (2 * delta); 0061 break; 0062 case 2: // blue 0063 if (R > G) 0064 *H = 240 + (120 * (R - G) + delta) / (2 * delta); 0065 else 0066 *H = 180 + (120 * (R - G + delta) + delta) / (2 * delta); 0067 break; 0068 } 0069 } 0070 } 0071 0072 void hsv_to_rgb(int H, int S, int V, int *R, int *G, int *B) 0073 { 0074 *R = *G = *B = V; 0075 0076 if (S != 0 && H != -1) { // chromatic 0077 0078 if (H >= 360) { 0079 // angle > 360 0080 H %= 360; 0081 } 0082 0083 unsigned int f = H % 60; 0084 H /= 60; 0085 unsigned int p = static_cast<unsigned int>(2 * V * (255 - S) + 255) / 510; 0086 0087 if (H & 1) { 0088 unsigned int q = static_cast<unsigned int>(2 * V * (15300 - S * f) + 15300) / 30600; 0089 switch (H) { 0090 case 1: 0091 *R = static_cast<int>(q); 0092 *G = static_cast<int>(V); 0093 *B = static_cast<int>(p); 0094 break; 0095 case 3: 0096 *R = static_cast<int>(p); 0097 *G = static_cast<int>(q); 0098 *B = static_cast<int>(V); 0099 break; 0100 case 5: 0101 *R = static_cast<int>(V); 0102 *G = static_cast<int>(p); 0103 *B = static_cast<int>(q); 0104 break; 0105 } 0106 } else { 0107 unsigned int t = static_cast<unsigned int>(2 * V * (15300 - (S * (60 - f))) + 15300) / 30600; 0108 switch (H) { 0109 case 0: 0110 *R = static_cast<int>(V); 0111 *G = static_cast<int>(t); 0112 *B = static_cast<int>(p); 0113 break; 0114 case 2: 0115 *R = static_cast<int>(p); 0116 *G = static_cast<int>(V); 0117 *B = static_cast<int>(t); 0118 break; 0119 case 4: 0120 *R = static_cast<int>(t); 0121 *G = static_cast<int>(p); 0122 *B = static_cast<int>(V); 0123 break; 0124 } 0125 } 0126 } 0127 } 0128 0129 #define EPSILON 1e-6 0130 #define UNDEFINED_HUE -1 0131 0132 void RGBToHSV(float r, float g, float b, float *h, float *s, float *v) 0133 { 0134 float max = qMax(r, qMax(g, b)); 0135 float min = qMin(r, qMin(g, b)); 0136 0137 *v = max; 0138 0139 if (max > EPSILON) { 0140 *s = (max - min) / max; 0141 } else { 0142 *s = 0; 0143 } 0144 0145 if (*s < EPSILON) { 0146 *h = UNDEFINED_HUE; 0147 } else { 0148 float delta = max - min; 0149 0150 if (r == max) { 0151 *h = (g - b) / delta; 0152 } else if (g == max) { 0153 *h = 2 + (b - r) / delta; 0154 } else { 0155 *h = 4 + (r - g) / delta; 0156 } 0157 0158 *h *= 60; 0159 if (*h < 0) { 0160 *h += 360; 0161 } 0162 } 0163 } 0164 0165 void HSVToRGB(float h, float s, float v, float *r, float *g, float *b) 0166 { 0167 if (s < EPSILON || h == UNDEFINED_HUE) { 0168 // Achromatic case 0169 0170 *r = v; 0171 *g = v; 0172 *b = v; 0173 } else { 0174 float f, p, q, t; 0175 int i; 0176 0177 if (h > 360 - EPSILON) { 0178 h -= 360; 0179 } 0180 0181 h /= 60; 0182 i = static_cast<int>(floor(h)); 0183 f = h - i; 0184 p = v * (1 - s); 0185 q = v * (1 - (s * f)); 0186 t = v * (1 - (s * (1 - f))); 0187 0188 switch (i) { 0189 case 0: 0190 *r = v; 0191 *g = t; 0192 *b = p; 0193 break; 0194 case 1: 0195 *r = q; 0196 *g = v; 0197 *b = p; 0198 break; 0199 case 2: 0200 *r = p; 0201 *g = v; 0202 *b = t; 0203 break; 0204 case 3: 0205 *r = p; 0206 *g = q; 0207 *b = v; 0208 break; 0209 case 4: 0210 *r = t; 0211 *g = p; 0212 *b = v; 0213 break; 0214 case 5: 0215 *r = v; 0216 *g = p; 0217 *b = q; 0218 break; 0219 } 0220 } 0221 } 0222 0223 void rgb_to_hls(quint8 red, quint8 green, quint8 blue, float * hue, float * lightness, float * saturation) 0224 { 0225 float r = red / 255.0; 0226 float g = green / 255.0; 0227 float b = blue / 255.0; 0228 float h = 0; 0229 float l = 0; 0230 float s = 0; 0231 0232 float max, min, delta; 0233 0234 max = qMax(r, g); 0235 max = qMax(max, b); 0236 0237 min = qMin(r, g); 0238 min = qMin(min, b); 0239 0240 delta = max - min; 0241 0242 l = (max + min) / 2; 0243 0244 if (delta == 0) { 0245 // This is a gray, no chroma... 0246 h = 0; 0247 s = 0; 0248 } else { 0249 if (l < 0.5) 0250 s = delta / (max + min); 0251 else 0252 s = delta / (2 - max - min); 0253 0254 float delta_r, delta_g, delta_b; 0255 0256 delta_r = ((max - r) / 6) / delta; 0257 delta_g = ((max - g) / 6) / delta; 0258 delta_b = ((max - b) / 6) / delta; 0259 0260 if (r == max) 0261 h = delta_b - delta_g; 0262 else if (g == max) 0263 h = (1.0 / 3) + delta_r - delta_b; 0264 else if (b == max) 0265 h = (2.0 / 3) + delta_g - delta_r; 0266 0267 if (h < 0) h += 1; 0268 if (h > 1) h += 1; 0269 0270 } 0271 0272 *hue = h * 360; 0273 *saturation = s; 0274 *lightness = l; 0275 } 0276 0277 float hue_value(float n1, float n2, float hue) 0278 { 0279 if (hue > 360) 0280 hue = hue - 360; 0281 else if (hue < 0) 0282 hue = hue + 360; 0283 if (hue < 60) 0284 return n1 + (((n2 - n1) * hue) / 60); 0285 else if (hue < 180) 0286 return n2; 0287 else if (hue < 240) 0288 return n1 + (((n2 - n1) *(240 - hue)) / 60); 0289 else return n1; 0290 } 0291 0292 0293 void hls_to_rgb(float h, float l, float s, quint8 * r, quint8 * g, quint8 * b) 0294 { 0295 float m1, m2; 0296 0297 if (l <= 0.5) 0298 m2 = l * (1 + s); 0299 else 0300 m2 = l + s - l * s; 0301 0302 m1 = 2 * l - m2; 0303 0304 *r = (quint8)(hue_value(m1, m2, h + 120) * 255 + 0.5); 0305 *g = (quint8)(hue_value(m1, m2, h) * 255 + 0.5); 0306 *b = (quint8)(hue_value(m1, m2, h - 120) * 255 + 0.5); 0307 0308 } 0309 0310 void rgb_to_hls(quint8 r, quint8 g, quint8 b, int * h, int * l, int * s) 0311 { 0312 float hue, saturation, lightness; 0313 0314 rgb_to_hls(r, g, b, &hue, &lightness, &saturation); 0315 *h = (int)(hue + 0.5); 0316 *l = (int)(lightness * 255 + 0.5); 0317 *s = (int)(saturation * 255 + 0.5); 0318 } 0319 0320 void hls_to_rgb(int h, int l, int s, quint8 * r, quint8 * g, quint8 * b) 0321 { 0322 float hue = h; 0323 float lightness = l / 255.0; 0324 float saturation = s / 255.0; 0325 0326 hls_to_rgb(hue, lightness, saturation, r, g, b); 0327 } 0328 0329 /* 0330 A Fast HSL-to-RGB Transform 0331 by Ken Fishkin 0332 from "Graphics Gems", Academic Press, 1990 0333 */ 0334 0335 void RGBToHSL(float r, float g, float b, float *h, float *s, float *l) 0336 { 0337 float v; 0338 float m; 0339 float vm; 0340 float r2, g2, b2; 0341 0342 v = qMax(r, g); 0343 v = qMax(v, b); 0344 m = qMin(r, g); 0345 m = qMin(m, b); 0346 0347 if ((*l = (m + v) / 2.0) <= 0.0) { 0348 *h = UNDEFINED_HUE; 0349 *s = 0; 0350 return; 0351 } 0352 if ((*s = vm = v - m) > 0.0) { 0353 *s /= (*l <= 0.5) ? (v + m) : 0354 (2.0 - v - m) ; 0355 } else { 0356 *h = UNDEFINED_HUE; 0357 return; 0358 } 0359 0360 0361 r2 = (v - r) / vm; 0362 g2 = (v - g) / vm; 0363 b2 = (v - b) / vm; 0364 0365 if (r == v) 0366 *h = (g == m ? 5.0 + b2 : 1.0 - g2); 0367 else if (g == v) 0368 *h = (b == m ? 1.0 + r2 : 3.0 - b2); 0369 else 0370 *h = (r == m ? 3.0 + g2 : 5.0 - r2); 0371 0372 *h *= 60; 0373 *h = fmod(*h, 360.0); 0374 } 0375 0376 void HSLToRGB(float h, float sl, float l, float *r, float *g, float *b) 0377 0378 { 0379 float v; 0380 0381 v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl); 0382 if (v <= 0) { 0383 *r = *g = *b = 0.0; 0384 } else { 0385 float m; 0386 float sv; 0387 int sextant; 0388 float fract, vsf, mid1, mid2; 0389 0390 m = l + l - v; 0391 sv = (v - m) / v; 0392 h = fmod(h, 360.0); 0393 h /= 60.0; 0394 sextant = static_cast<int>(h); 0395 fract = h - sextant; 0396 vsf = v * sv * fract; 0397 mid1 = m + vsf; 0398 mid2 = v - vsf; 0399 switch (sextant) { 0400 case 0: *r = v; *g = mid1; *b = m; break; 0401 case 1: *r = mid2; *g = v; *b = m; break; 0402 case 2: *r = m; *g = v; *b = mid1; break; 0403 case 3: *r = m; *g = mid2; *b = v; break; 0404 case 4: *r = mid1; *g = m; *b = v; break; 0405 case 5: *r = v; *g = m; *b = mid2; break; 0406 } 0407 } 0408 } 0409 0410 //functions for converting from and back to HSI 0411 void HSIToRGB(const qreal h,const qreal s, const qreal i, qreal *red, qreal *green, qreal *blue) 0412 {//This function takes H, S and I values, which are converted to rgb. 0413 qreal onethird = 1.0/3.0; 0414 HSYToRGB(h, s, i, red, green, blue, onethird, onethird, onethird); 0415 } 0416 void RGBToHSI(qreal r,qreal g, qreal b, qreal *h, qreal *s, qreal *i) 0417 { 0418 qreal onethird = 1.0/3.0; 0419 RGBToHSY(r, g, b, h, s, i, onethird, onethird, onethird); 0420 0421 } 0422 //functions for converting from and back to hsy' 0423 void HSYToRGB(const qreal h,const qreal s, const qreal y, qreal *red, qreal *green, qreal *blue, qreal R, qreal G, qreal B) 0424 {//This function takes H, S and Y values, which are converted to rgb. 0425 //Those are then used to create a qcolor. 0426 qreal hue = 0.0; 0427 qreal sat = 0.0; 0428 qreal luma = 0.0; 0429 if (h>1.0 || h<0.0){hue=fmod(h, 1.0);} else {hue=h;} 0430 if (s<0.0){sat=0.0;} else {sat=s;} 0431 //if (y>1.0){luma=1.0;} 0432 if (y<0.0){luma=0.0;} 0433 else {luma=y;} 0434 0435 qreal segment = 0.166667;//1/6; 0436 qreal r=0.0; 0437 qreal g=0.0; 0438 qreal b=0.0; 0439 //weights for rgb to Y'(Luma), these are the same weights used in color space maths and the desaturate. 0440 //This is not luminance or luminosity, it just quacks like it. 0441 //qreal R=0.299; 0442 //qreal G=0.587; 0443 //qreal B=0.114; 0444 //The intermediary variables for the weighted HSL forumala, based on the HSL in KoColorConversions. 0445 qreal max_sat, m, fract, luma_a, chroma, x; 0446 if (hue >= 0.0 && hue < (segment) ) { 0447 //need to treat this as a weighted hsl thingy. 0448 //so first things first, at which luma is the maximum saturation for this hue? 0449 //between R and G+R (yellow) 0450 max_sat = R + ( G*(hue*6) ); 0451 if (luma<=max_sat){luma_a = (luma/max_sat)*0.5; chroma=sat*2*luma_a;} 0452 else {luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; chroma=sat*(2-2*luma_a);} 0453 0454 fract = hue*6.0; 0455 x = (1-fabs(fmod(fract,2)-1))*chroma; 0456 r = chroma; g=x; b=0; 0457 m = luma-( (R*r)+(B*b)+(G*g) ); 0458 r += m; g += m; b += m; 0459 } else if (hue >= (segment) && hue < (2.0*segment) ) { 0460 max_sat = (G+R) - (R*(hue-segment)*6); 0461 0462 if (luma<max_sat) { 0463 luma_a = (luma/max_sat)*0.5; chroma=sat*(2*luma_a); 0464 } else { 0465 luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; chroma=sat*(2-2*luma_a); 0466 } 0467 0468 fract = hue*6.0; 0469 x = (1-fabs(fmod(fract,2)-1) )*chroma; 0470 r = x; g=chroma; b=0; 0471 m = luma-( (R*r)+(B*b)+(G*g) ); 0472 r += m; g += m; b += m; 0473 } else if (hue >= (2.0*segment) && hue < (3.0*segment) ) { 0474 max_sat = G + (B*(hue-2.0*segment)*6); 0475 if (luma<max_sat) { 0476 luma_a = (luma/max_sat)*0.5; chroma=sat*(2*luma_a); 0477 } else { 0478 luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; chroma=sat*(2-2*luma_a); 0479 } 0480 fract = hue*6.0; 0481 x = (1-fabs(fmod(fract,2)-1) )*chroma; 0482 r = 0; g=chroma; b=x; 0483 m = luma-( (R*r)+(B*b)+(G*g) ); 0484 r += m; g += m; b += m; 0485 } else if (hue >= (3.0*segment) && hue < (4.0*segment) ) { 0486 max_sat = (G+B) - (G*(hue-3.0*segment)*6); 0487 if (luma<max_sat){ 0488 luma_a = (luma/max_sat)*0.5; chroma=sat*(2*luma_a); 0489 } else { 0490 luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; chroma=sat*(2-2*luma_a); 0491 } 0492 0493 fract = hue*6.0; 0494 x = (1-fabs(fmod(fract,2)-1) )*chroma; 0495 r = 0; g=x; b=chroma; 0496 m = luma-( (R*r)+(B*b)+(G*g) ); 0497 r += m; g += m; b += m; 0498 } else if (hue >= (4.0*segment) && hue < (5*segment) ) { 0499 max_sat = B + (R*((hue-4.0*segment)*6)); 0500 if (luma<max_sat) { 0501 luma_a = (luma/max_sat)*0.5; chroma=sat*(2*luma_a); 0502 } else { 0503 luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; chroma=sat*(2-2*luma_a); 0504 } 0505 fract = hue*6.0; 0506 x = (1-fabs(fmod(fract,2)-1) )*chroma; 0507 r = x; g=0; b=chroma; 0508 m = luma-( (R*r)+(B*b)+(G*g) ); 0509 r += m; g += m; b += m; 0510 } else if (hue >= (5.0*segment) && hue <= 1.0) { 0511 max_sat = (B+R) - (B*(hue-5.0*segment)*6); 0512 if (luma<max_sat){ 0513 luma_a = (luma/max_sat)*0.5; chroma=sat*(2*luma_a); 0514 } else { 0515 luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; chroma=sat*(2-2*luma_a); 0516 } 0517 fract = hue*6.0; 0518 x = (1-fabs(fmod(fract,2)-1) )*chroma; 0519 r = chroma; g=0; b=x; 0520 m = luma-( (R*r)+(B*b)+(G*g) ); 0521 r += m; g += m; b += m; 0522 } else { 0523 r=0.0; 0524 g=0.0; 0525 b=0.0; 0526 } 0527 0528 //dbgPigment<<"red: "<<r<<", green: "<<g<<", blue: "<<b; 0529 //if (r>1.0){r=1.0;} 0530 //if (g>1.0){g=1.0;} 0531 //if (b>1.0){b=1.0;} 0532 //don't limit upwards due to floating point. 0533 if (r<0.0){r=0.0;} 0534 if (g<0.0){g=0.0;} 0535 if (b<0.0){b=0.0;} 0536 0537 *red=r; 0538 *green=g; 0539 *blue=b; 0540 } 0541 void RGBToHSY(const qreal r,const qreal g,const qreal b, qreal *h, qreal *s, qreal *y, qreal R, qreal G, qreal B) 0542 { 0543 //This is LUMA btw, not Luminance. 0544 //Using these RGB values, we calculate the H, S and I. 0545 qreal red; qreal green; qreal blue; 0546 if (r<0.0){red=0.0;} else {red=r;} 0547 if (g<0.0){green=0.0;} else {green=g;} 0548 if (b<0.0){blue=0.0;} else {blue=b;} 0549 0550 qreal minval = qMin(r, qMin(g, b)); 0551 qreal maxval = qMax(r, qMax(g, b)); 0552 qreal hue = 0.0; 0553 qreal sat = 0.0; 0554 qreal luma = 0.0; 0555 //weights for rgb, these are the same weights used in color space maths and the desaturate. 0556 //qreal R=0.299; 0557 //qreal G=0.587; 0558 //qreal B=0.114; 0559 luma=(R*red+G*green+B*blue); 0560 qreal luma_a=luma;//defined later 0561 qreal chroma = maxval-minval; 0562 qreal max_sat=0.5; 0563 if(chroma==0) { 0564 hue = 0.0; 0565 sat = 0.0; 0566 } else { 0567 //the following finds the hue 0568 0569 if(maxval==r) { 0570 //hue = fmod(((g-b)/chroma), 6.0); 0571 //above doesn't work so let's try this one: 0572 if (minval==b) { 0573 hue = (g-b)/chroma; 0574 } else { 0575 hue = (g-b)/chroma + 6.0; 0576 } 0577 } else if(maxval==g) { 0578 hue = (b-r)/chroma + 2.0; 0579 } else if(maxval==b) { 0580 hue = (r-g)/chroma + 4.0; 0581 } 0582 0583 hue /=6.0;//this makes sure that hue is in the 0-1.0 range. 0584 //Most HSY formula will tell you that Sat=Chroma. However, this HSY' formula tries to be a 0585 //weighted HSL formula, where instead of 0.5, we search for a Max_Sat value, which is the Y' 0586 //at which the saturation is maximum. 0587 //This requires using the hue, and combining the weighting values accordingly. 0588 qreal segment = 0.166667; 0589 if (hue>1.0 || hue<0.0) { 0590 hue=fmod(hue, 1.0); 0591 } 0592 0593 if (hue>=0.0 && hue<segment) { 0594 max_sat = R + G*(hue*6); 0595 } else if (hue>=segment && hue<(2.0*segment)) { 0596 max_sat = (G+R) - R*((hue-segment)*6); 0597 } else if (hue>=(2.0*segment) && hue<(3.0*segment)) { 0598 max_sat = G + B*((hue-2.0*segment)*6); 0599 } else if (hue>=(3.0*segment) && hue<(4.0*segment)) { 0600 max_sat = (B+G) - G*((hue-3.0*segment)*6); 0601 } else if (hue>=(4.0*segment) && hue<(5.0*segment)) { 0602 max_sat = (B) + R*((hue-4.0*segment)*6); 0603 } else if (hue>=(5.0*segment) && hue<=1.0) { 0604 max_sat = (R+B) - B*((hue-5.0*segment)*6); 0605 } else { 0606 max_sat=0.5; 0607 } 0608 0609 if(max_sat>1.0 || max_sat<0.0){ //This should not show up during normal use 0610 max_sat=(fmod(max_sat,1.0)); 0611 } //If it does, it'll try to correct, but it's not good! 0612 0613 //This is weighting the luma for the saturation) 0614 if (luma <= max_sat) { 0615 luma_a = (luma/max_sat)*0.5; 0616 } else{ 0617 luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; 0618 } 0619 0620 if (chroma > 0.0) { 0621 sat = (luma <= max_sat) ? (chroma/ (2*luma_a) ) :(chroma/(2.0-(2*luma_a) ) ) ; 0622 } 0623 } 0624 0625 //if (sat>1.0){sat=1.0;} 0626 //if (luma>1.0){luma=1.0;} 0627 if (sat<0.0){sat=0.0;} 0628 if (luma<0.0){luma=0.0;} 0629 0630 *h=hue; 0631 *s=sat; 0632 *y=luma; 0633 0634 0635 } 0636 //Extra: Functions for converting from and back to HCI. Where the HSI function is forced cylindrical, HCI is a 0637 //double cone. This is for compatibility purposes, and of course, making future programmers who expect a double-cone 0638 // function less sad. These algorithms were taken from wikipedia. 0639 0640 void HCIToRGB(const qreal h, const qreal c, const qreal i, qreal *red, qreal *green, qreal *blue) 0641 { 0642 //This function may not be correct, but it's based on the HCY function on the basis of seeing HCI as similar 0643 //to the weighted HCY, but assuming that the weights are the same(one-third). 0644 qreal hue=0.0; 0645 qreal chroma=0.0; 0646 qreal intensity=0.0; 0647 if(i<0.0){intensity = 0.0;} else{intensity = i;} 0648 if (h>1.0 || h<0.0){hue=fmod(h, 1.0);} else {hue=h;} 0649 if(c<0.0){chroma = 0.0;} else{chroma = c;} 0650 const qreal onethird = 1.0/3.0; 0651 qreal r=0.0; 0652 qreal g=0.0; 0653 qreal b=0.0; 0654 0655 int fract = static_cast<int>(hue*6.0); 0656 qreal x = (1-fabs(fmod(hue*6.0,2)-1) )*chroma; 0657 switch (fract) { 0658 case 0:r = chroma; g=x; b=0;break; 0659 case 1:r = x; g=chroma; b=0;break; 0660 case 2:r = 0; g=chroma; b=x;break; 0661 case 3:r = 0; g=x; b=chroma;break; 0662 case 4:r = x; g=0; b=chroma;break; 0663 case 5:r = chroma; g=0; b=x;break; 0664 } 0665 qreal m = intensity-( onethird*(r+g+b) ); 0666 r += m; g += m; b += m; 0667 0668 *red=r; 0669 *green=g; 0670 *blue=b; 0671 } 0672 0673 void RGBToHCI(const qreal r,const qreal g,const qreal b, qreal *h, qreal *c, qreal *i) 0674 { 0675 qreal minval = qMin(r, qMin(g, b)); 0676 qreal maxval = qMax(r, qMax(g, b)); 0677 qreal hue = 0.0; 0678 qreal sat = 0.0; 0679 qreal intensity = 0.0; 0680 intensity=(r+g+b)/3.0; 0681 qreal chroma = maxval-minval; 0682 if(chroma==0) { 0683 hue = 0.0; 0684 sat = 0.0; 0685 } else { 0686 //the following finds the hue 0687 0688 if(maxval==r) { 0689 if (minval==b) { 0690 hue = (g-b)/chroma; 0691 } else { 0692 hue = (g-b)/chroma + 6.0; 0693 } 0694 } else if(maxval==g) { 0695 hue = (b-r)/chroma + 2.0; 0696 } else if(maxval==b) { 0697 hue = (r-g)/chroma + 4.0; 0698 } 0699 hue /=6.0;//this makes sure that hue is in the 0-1.0 range. 0700 sat= 1-(minval/intensity); 0701 } 0702 0703 *h=hue; 0704 *c=sat; 0705 *i=intensity; 0706 0707 } 0708 void HCYToRGB(const qreal h, const qreal c, const qreal y, qreal *red, qreal *green, qreal *blue, qreal R, qreal G, qreal B) 0709 { 0710 qreal hue=0.0; 0711 qreal chroma=c; 0712 qreal luma=y; 0713 if (h>1.0 || h<0.0){hue=(fmod((h*2.0), 2.0))/2.0;} else {hue=h;} 0714 //const qreal R=0.299; 0715 //const qreal G=0.587; 0716 //const qreal B=0.114; 0717 qreal r=0.0; 0718 qreal g=0.0; 0719 qreal b=0.0; 0720 0721 int fract =static_cast<int>(hue*6.0); 0722 qreal x = (1-fabs(fmod(hue*6.0,2)-1) )*chroma; 0723 switch (fract) { 0724 case 0:r = chroma; g=x; b=0;break; 0725 case 1:r = x; g=chroma; b=0;break; 0726 case 2:r = 0; g=chroma; b=x;break; 0727 case 3:r = 0; g=x; b=chroma;break; 0728 case 4:r = x; g=0; b=chroma;break; 0729 case 5:r = chroma; g=0; b=x;break; 0730 } 0731 qreal m = luma-( (R*r)+(B*b)+(G*g) ); 0732 r += m; g += m; b += m; 0733 0734 *red=r; 0735 *green=g; 0736 *blue=b; 0737 } 0738 0739 void RGBToHCY(const qreal r,const qreal g,const qreal b, qreal *h, qreal *c, qreal *y, qreal R, qreal G, qreal B) 0740 { 0741 qreal minval = qMin(r, qMin(g, b)); 0742 qreal maxval = qMax(r, qMax(g, b)); 0743 qreal hue = 0.0; 0744 qreal chroma = 0.0; 0745 qreal luma = 0.0; 0746 //weights for rgb, these are the same weights used in color space maths and the desaturate. 0747 //qreal R=0.299; 0748 //qreal G=0.587; 0749 //qreal B=0.114; 0750 luma=(R*r+G*g+B*b); 0751 chroma = maxval-minval; 0752 0753 if(chroma==0) { 0754 hue = 0.0; 0755 } 0756 else { 0757 //the following finds the hue 0758 0759 if(maxval==r) { 0760 //hue = fmod(((g-b)/chroma), 6.0); 0761 //above doesn't work so let's try this one: 0762 if (minval==b) { 0763 hue = (g-b)/chroma; 0764 } else { 0765 hue = (g-b)/chroma + 6.0; 0766 } 0767 } else if(maxval==g) { 0768 hue = (b-r)/chroma + 2.0; 0769 } else if(maxval==b) { 0770 hue = (r-g)/chroma + 4.0; 0771 } 0772 hue /=6.0;//this makes sure that hue is in the 0-1.0 range. 0773 } 0774 if (chroma<0.0){chroma=0.0;} 0775 if (luma<0.0){luma=0.0;} 0776 0777 *h=qBound(0.0,hue,1.0); 0778 *c=chroma; 0779 *y=luma; 0780 0781 } 0782 void RGBToYUV(const qreal r,const qreal g,const qreal b, qreal *y, qreal *u, qreal *v, qreal R, qreal G, qreal B) 0783 { 0784 qreal uvmax = 0.5; 0785 qreal luma = R*r+G*g+B*b; 0786 qreal chromaBlue = uvmax*( (b - luma) / (1.0-B) ); 0787 qreal chromaRed = uvmax*( (r - luma) / (1.0-R) ); 0788 0789 *y = luma; //qBound(0.0,luma,1.0); 0790 *u = chromaBlue+uvmax;//qBound(0.0,chromaBlue+ uvmax,1.0); 0791 *v = chromaRed+uvmax;//qBound(0.0,chromaRed + uvmax,1.0); 0792 } 0793 void YUVToRGB(const qreal y, const qreal u, const qreal v, qreal *r, qreal *g, qreal *b, qreal R, qreal G, qreal B) 0794 { 0795 qreal uvmax = 0.5; 0796 qreal chromaBlue = u-uvmax;//qBound(0.0,u,1.0)- uvmax;//put into -0.5-+0.5 range// 0797 qreal chromaRed = v-uvmax;//qBound(0.0,v,1.0)- uvmax; 0798 0799 qreal negB = 1.0-B; 0800 qreal negR = 1.0-R; 0801 qreal red = y+(chromaRed * (negR / uvmax) ); 0802 qreal green = y-(chromaBlue * ((B*negB) / (uvmax*G)) ) - (chromaRed* ((R*negR) / (uvmax*G))); 0803 qreal blue = y+(chromaBlue * (negB / uvmax) ); 0804 0805 *r=red;//qBound(0.0,red ,1.0); 0806 *g=green;//qBound(0.0,green,1.0); 0807 *b=blue;//qBound(0.0,blue ,1.0); 0808 } 0809 0810 void LabToLCH(const qreal l, const qreal a, const qreal b, qreal *L, qreal *C, qreal *H) 0811 { 0812 qreal atemp = (a - 0.5)*10.0;//the multiplication is only so that we get out of floating-point maths 0813 qreal btemp = (b - 0.5)*10.0; 0814 *L=qBound(0.0,l,1.0); 0815 *C=sqrt( pow(atemp,2.0) + pow(btemp,2.0) )*0.1; 0816 qreal hue = (atan2(btemp,atemp))* 180.0 / M_PI; 0817 0818 if (hue<0.0) { 0819 hue+=360.0; 0820 } else { 0821 hue = fmod(hue, 360.0); 0822 } 0823 *H=hue/360.0; 0824 } 0825 0826 void LCHToLab(const qreal L, const qreal C, const qreal H, qreal *l, qreal *a, qreal *b) 0827 { 0828 qreal chroma = qBound(0.0,C,1.0); 0829 qreal hue = (qBound(0.0,H,1.0)*360.0)* M_PI / 180.0; 0830 *l=qBound(0.0,L,1.0); 0831 *a=(chroma * cos(hue) ) + 0.5; 0832 *b=(chroma * sin(hue) ) + 0.5; 0833 } 0834 0835 void XYZToxyY(const qreal X, const qreal Y, const qreal Z, qreal *x, qreal *y, qreal *yY) 0836 { 0837 qreal Xb = X; 0838 qreal Yb = Y; 0839 qreal Zb = Z; 0840 *x=Xb/(Xb+Yb+Zb); 0841 *y=Yb/(Xb+Yb+Zb); 0842 *yY=Yb; 0843 } 0844 void xyYToXYZ(const qreal x, const qreal y, const qreal yY, qreal *X, qreal *Y, qreal *Z) 0845 { 0846 qreal xb = x; 0847 qreal yb = y; 0848 qreal yYb = yY; 0849 *X=(xb*yYb)/yb; 0850 *Z=((1.0-xb-yb)*yYb)/yb; 0851 *Y=yYb; 0852 } 0853 0854 void CMYToCMYK(qreal *c, qreal *m, qreal *y, qreal *k) 0855 { 0856 qreal cyan, magenta, yellow, key = 1.0; 0857 cyan = *c; 0858 magenta = *m; 0859 yellow = *y; 0860 if ( cyan < key ) {key = cyan;} 0861 if ( magenta < key ) {key = magenta;} 0862 if ( yellow < key ) {key = yellow;} 0863 0864 if ( key == 1 ) { //Black 0865 cyan = 0; 0866 magenta = 0; 0867 yellow = 0; 0868 } 0869 else { 0870 cyan = ( cyan - key ) / ( 1.0 - key ); 0871 magenta = ( magenta - key ) / ( 1.0 - key ); 0872 yellow = ( yellow - key ) / ( 1.0 - key ); 0873 } 0874 0875 *c=qBound(0.0,cyan ,1.0); 0876 *m=qBound(0.0,magenta,1.0); 0877 *y=qBound(0.0,yellow ,1.0); 0878 *k=qBound(0.0,key ,1.0); 0879 } 0880 0881 /*code from easyrgb.com*/ 0882 void CMYKToCMY(qreal *c, qreal *m, qreal *y, qreal *k) 0883 { 0884 qreal key = *k; 0885 qreal cyan = *c; 0886 qreal magenta = *m; 0887 qreal yellow = *y; 0888 0889 cyan = ( cyan * ( 1.0 - key ) + key ); 0890 magenta = ( magenta * ( 1.0 - key ) + key ); 0891 yellow = ( yellow * ( 1.0 - key ) + key ); 0892 0893 *c=qBound(0.0,cyan ,1.0); 0894 *m=qBound(0.0,magenta,1.0); 0895 *y=qBound(0.0,yellow ,1.0); 0896 }