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