Blender  V2.59
math_color.c
Go to the documentation of this file.
00001 /*
00002  * $Id: math_color.c 37783 2011-06-24 03:49:56Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  
00023  * The Original Code is: some of this file.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  * */
00027 
00033 #include <assert.h>
00034 
00035 #include "BLI_math.h"
00036 
00037 void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b)
00038 {
00039         int i;
00040         float f, p, q, t;
00041 
00042         if(s==0.0f) {
00043                 *r = v;
00044                 *g = v;
00045                 *b = v;
00046         }
00047         else {
00048                 h= (h - floorf(h))*6.0f;
00049 
00050                 i = (int)floorf(h);
00051                 f = h - i;
00052                 p = v*(1.0f-s);
00053                 q = v*(1.0f-(s*f));
00054                 t = v*(1.0f-(s*(1.0f-f)));
00055                 
00056                 switch (i) {
00057                 case 0 :
00058                         *r = v;
00059                         *g = t;
00060                         *b = p;
00061                         break;
00062                 case 1 :
00063                         *r = q;
00064                         *g = v;
00065                         *b = p;
00066                         break;
00067                 case 2 :
00068                         *r = p;
00069                         *g = v;
00070                         *b = t;
00071                         break;
00072                 case 3 :
00073                         *r = p;
00074                         *g = q;
00075                         *b = v;
00076                         break;
00077                 case 4 :
00078                         *r = t;
00079                         *g = p;
00080                         *b = v;
00081                         break;
00082                 case 5 :
00083                         *r = v;
00084                         *g = p;
00085                         *b = q;
00086                         break;
00087                 }
00088         }
00089 }
00090 
00091 void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv)
00092 {
00093         float y, u, v;
00094         y= 0.299f*r + 0.587f*g + 0.114f*b;
00095         u=-0.147f*r - 0.289f*g + 0.436f*b;
00096         v= 0.615f*r - 0.515f*g - 0.100f*b;
00097         
00098         *ly=y;
00099         *lu=u;
00100         *lv=v;
00101 }
00102 
00103 void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb)
00104 {
00105         float r, g, b;
00106         r=y+1.140f*v;
00107         g=y-0.394f*u - 0.581f*v;
00108         b=y+2.032f*u;
00109         
00110         *lr=r;
00111         *lg=g;
00112         *lb=b;
00113 }
00114 
00115 /* The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f */
00116 /* Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
00117 void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, int colorspace)
00118 {
00119         float sr,sg, sb;
00120         float y = 128.f, cr = 128.f, cb = 128.f;
00121         
00122         sr=255.0f*r;
00123         sg=255.0f*g;
00124         sb=255.0f*b;
00125         
00126         switch (colorspace) {
00127         case BLI_YCC_ITU_BT601 :
00128                 y=(0.257f*sr)+(0.504f*sg)+(0.098f*sb)+16.0f;
00129                 cb=(-0.148f*sr)-(0.291f*sg)+(0.439f*sb)+128.0f;
00130                 cr=(0.439f*sr)-(0.368f*sg)-(0.071f*sb)+128.0f;
00131                 break;
00132         case BLI_YCC_ITU_BT709 :
00133                 y=(0.183f*sr)+(0.614f*sg)+(0.062f*sb)+16.0f;
00134                 cb=(-0.101f*sr)-(0.338f*sg)+(0.439f*sb)+128.0f;
00135                 cr=(0.439f*sr)-(0.399f*sg)-(0.040f*sb)+128.0f;
00136                 break;
00137         case BLI_YCC_JFIF_0_255 :
00138                 y=(0.299f*sr)+(0.587f*sg)+(0.114f*sb);
00139                 cb=(-0.16874f*sr)-(0.33126f*sg)+(0.5f*sb)+128.0f;
00140                 cr=(0.5f*sr)-(0.41869f*sg)-(0.08131f*sb)+128.0f;
00141                 break;
00142         default:
00143                 assert(!"invalid colorspace");
00144         }
00145         
00146         *ly=y;
00147         *lcb=cb;
00148         *lcr=cr;
00149 }
00150 
00151 
00152 /* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
00153 /* RGB outputs are in the range 0 - 1.0f */
00154 /* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */
00155 void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb, int colorspace)
00156 {
00157         float r = 128.f, g = 128.f, b = 128.f;
00158         
00159         switch (colorspace) {
00160         case BLI_YCC_ITU_BT601 :
00161                 r=1.164f*(y-16.0f)+1.596f*(cr-128.0f);
00162                 g=1.164f*(y-16.0f)-0.813f*(cr-128.0f)-0.392f*(cb-128.0f);
00163                 b=1.164f*(y-16.0f)+2.017f*(cb-128.0f);
00164                 break;
00165         case BLI_YCC_ITU_BT709 :
00166                 r=1.164f*(y-16.0f)+1.793f*(cr-128.0f);
00167                 g=1.164f*(y-16.0f)-0.534f*(cr-128.0f)-0.213f*(cb-128.0f);
00168                 b=1.164f*(y-16.0f)+2.115f*(cb-128.0f);
00169                 break;
00170         case BLI_YCC_JFIF_0_255 :
00171                 r=y+1.402f*cr - 179.456f;
00172                 g=y-0.34414f*cb - 0.71414f*cr + 135.45984f;
00173                 b=y+1.772f*cb - 226.816f;
00174                 break;
00175         default:
00176                 assert(!"invalid colorspace");
00177         }
00178         *lr=r/255.0f;
00179         *lg=g/255.0f;
00180         *lb=b/255.0f;
00181 }
00182 
00183 void hex_to_rgb(char *hexcol, float *r, float *g, float *b)
00184 {
00185         unsigned int ri, gi, bi;
00186 
00187         if (hexcol[0] == '#') hexcol++;
00188 
00189         if (sscanf(hexcol, "%02x%02x%02x", &ri, &gi, &bi)==3) {
00190                 *r = ri / 255.0f;
00191                 *g = gi / 255.0f;
00192                 *b = bi / 255.0f;
00193                 CLAMP(*r, 0.0f, 1.0f);
00194                 CLAMP(*g, 0.0f, 1.0f);
00195                 CLAMP(*b, 0.0f, 1.0f);
00196         }
00197         else {
00198                 /* avoid using un-initialized vars */
00199                 *r= *g= *b= 0.0f;
00200         }
00201 }
00202 
00203 void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv)
00204 {
00205         float h, s, v;
00206         float cmax, cmin, cdelta;
00207         float rc, gc, bc;
00208 
00209         cmax = r;
00210         cmin = r;
00211         cmax = (g>cmax ? g:cmax);
00212         cmin = (g<cmin ? g:cmin);
00213         cmax = (b>cmax ? b:cmax);
00214         cmin = (b<cmin ? b:cmin);
00215 
00216         v = cmax;               /* value */
00217         if (cmax != 0.0f)
00218                 s = (cmax - cmin)/cmax;
00219         else {
00220                 s = 0.0f;
00221         }
00222         if (s == 0.0f)
00223                 h = -1.0f;
00224         else {
00225                 cdelta = cmax-cmin;
00226                 rc = (cmax-r)/cdelta;
00227                 gc = (cmax-g)/cdelta;
00228                 bc = (cmax-b)/cdelta;
00229                 if (r==cmax)
00230                         h = bc-gc;
00231                 else
00232                         if (g==cmax)
00233                                 h = 2.0f+rc-bc;
00234                         else
00235                                 h = 4.0f+gc-rc;
00236                 h = h*60.0f;
00237                 if (h < 0.0f)
00238                         h += 360.0f;
00239         }
00240         
00241         *ls = s;
00242         *lh = h / 360.0f;
00243         if(*lh < 0.0f) *lh= 0.0f;
00244         *lv = v;
00245 }
00246 
00247 void rgb_to_hsv_compat(float r, float g, float b, float *lh, float *ls, float *lv)
00248 {
00249         float orig_h= *lh;
00250         float orig_s= *ls;
00251 
00252         rgb_to_hsv(r, g, b, lh, ls, lv);
00253 
00254         if(*lv <= 0.0f) {
00255                 *lh= orig_h;
00256                 *ls= orig_s;
00257         }
00258         else if (*ls <= 0.0f) {
00259                 *lh= orig_h;
00260         }
00261 
00262         if(*lh==0.0f && orig_h >= 1.0f) {
00263                 *lh= 1.0f;
00264         }
00265 }
00266 
00267 /*http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html */
00268 
00269 void xyz_to_rgb(float xc, float yc, float zc, float *r, float *g, float *b, int colorspace)
00270 {
00271         switch (colorspace) { 
00272         case BLI_XYZ_SMPTE:
00273                 *r = (3.50570f   * xc) + (-1.73964f      * yc) + (-0.544011f * zc);
00274                 *g = (-1.06906f  * xc) + (1.97781f       * yc) + (0.0351720f * zc);
00275                 *b = (0.0563117f * xc) + (-0.196994f * yc) + (1.05005f   * zc);
00276                 break;
00277         case BLI_XYZ_REC709_SRGB:
00278                 *r = (3.240476f  * xc) + (-1.537150f * yc) + (-0.498535f * zc);
00279                 *g = (-0.969256f * xc) + (1.875992f  * yc) + (0.041556f  * zc);
00280                 *b = (0.055648f  * xc) + (-0.204043f * yc) + (1.057311f  * zc);
00281                 break;
00282         case BLI_XYZ_CIE:
00283                 *r = (2.28783848734076f * xc) + (-0.833367677835217f    * yc) + (-0.454470795871421f    * zc);
00284                 *g = (-0.511651380743862f * xc) + (1.42275837632178f * yc) + (0.0888930017552939f * zc);
00285                 *b = (0.00572040983140966f      * xc) + (-0.0159068485104036f   * yc) + (1.0101864083734f       * zc);
00286                 break;
00287         }
00288 }
00289 
00290 /* we define a 'cpack' here as a (3 byte color code) number that can be expressed like 0xFFAA66 or so.
00291    for that reason it is sensitive for endianness... with this function it works correctly
00292 */
00293 
00294 unsigned int hsv_to_cpack(float h, float s, float v)
00295 {
00296         short r, g, b;
00297         float rf, gf, bf;
00298         unsigned int col;
00299         
00300         hsv_to_rgb(h, s, v, &rf, &gf, &bf);
00301         
00302         r= (short)(rf*255.0f);
00303         g= (short)(gf*255.0f);
00304         b= (short)(bf*255.0f);
00305         
00306         col= ( r + (g*256) + (b*256*256) );
00307         return col;
00308 }
00309 
00310 
00311 unsigned int rgb_to_cpack(float r, float g, float b)
00312 {
00313         int ir, ig, ib;
00314         
00315         ir= (int)floor(255.0f*r);
00316         if(ir<0) ir= 0; else if(ir>255) ir= 255;
00317         ig= (int)floor(255.0f*g);
00318         if(ig<0) ig= 0; else if(ig>255) ig= 255;
00319         ib= (int)floor(255.0f*b);
00320         if(ib<0) ib= 0; else if(ib>255) ib= 255;
00321         
00322         return (ir+ (ig*256) + (ib*256*256));
00323 }
00324 
00325 void cpack_to_rgb(unsigned int col, float *r, float *g, float *b)
00326 {
00327         
00328         *r= (float)((col)&0xFF);
00329         *r /= 255.0f;
00330 
00331         *g= (float)(((col)>>8)&0xFF);
00332         *g /= 255.0f;
00333 
00334         *b= (float)(((col)>>16)&0xFF);
00335         *b /= 255.0f;
00336 }
00337 
00338 void rgb_byte_to_float(const unsigned char *in, float *out)
00339 {
00340         out[0]= ((float)in[0]) / 255.0f;
00341         out[1]= ((float)in[1]) / 255.0f;
00342         out[2]= ((float)in[2]) / 255.0f;
00343 }
00344 
00345 void rgb_float_to_byte(const float *in, unsigned char *out)
00346 {
00347         int r, g, b;
00348         
00349         r= (int)(in[0] * 255.0f);
00350         g= (int)(in[1] * 255.0f);
00351         b= (int)(in[2] * 255.0f);
00352         
00353         out[0]= (char)((r <= 0)? 0 : (r >= 255)? 255 : r);
00354         out[1]= (char)((g <= 0)? 0 : (g >= 255)? 255 : g);
00355         out[2]= (char)((b <= 0)? 0 : (b >= 255)? 255 : b);
00356 }
00357 
00358 /* ********************************* color transforms ********************************* */
00359 
00360 
00361 void gamma_correct(float *c, float gamma)
00362 {
00363         *c = powf((*c), gamma);
00364 }
00365 
00366 float rec709_to_linearrgb(float c)
00367 {
00368         if (c < 0.081f)
00369                 return (c < 0.0f)? 0.0f: c * (1.0f/4.5f);
00370         else
00371                 return powf((c + 0.099f)*(1.0f/1.099f), (1.0f/0.45f));
00372 }
00373 
00374 float linearrgb_to_rec709(float c)
00375 {
00376         if (c < 0.018f)
00377                 return (c < 0.0f)? 0.0f: c * 4.5f;
00378         else
00379                 return 1.099f * powf(c, 0.45f) - 0.099f;
00380 }
00381 
00382 float srgb_to_linearrgb(float c)
00383 {
00384         if (c < 0.04045f)
00385                 return (c < 0.0f)? 0.0f: c * (1.0f/12.92f);
00386         else
00387                 return powf((c + 0.055f)*(1.0f/1.055f), 2.4f);
00388 }
00389 
00390 float linearrgb_to_srgb(float c)
00391 {
00392         if (c < 0.0031308f)
00393                 return (c < 0.0f)? 0.0f: c * 12.92f;
00394         else
00395                 return  1.055f * powf(c, 1.0f/2.4f) - 0.055f;
00396 }
00397 
00398 void srgb_to_linearrgb_v3_v3(float *col_to, float *col_from)
00399 {
00400         col_to[0] = srgb_to_linearrgb(col_from[0]);
00401         col_to[1] = srgb_to_linearrgb(col_from[1]);
00402         col_to[2] = srgb_to_linearrgb(col_from[2]);
00403 }
00404 
00405 void linearrgb_to_srgb_v3_v3(float *col_to, float *col_from)
00406 {
00407         col_to[0] = linearrgb_to_srgb(col_from[0]);
00408         col_to[1] = linearrgb_to_srgb(col_from[1]);
00409         col_to[2] = linearrgb_to_srgb(col_from[2]);
00410 }
00411 
00412 /* todo, should these be moved elsewhere?, they dont belong in imbuf */
00413 void srgb_to_linearrgb_rgba_buf(float *col, int tot)
00414 {
00415         while(tot--) {
00416                 srgb_to_linearrgb_v3_v3(col, col);
00417                 col += 4;
00418         }
00419 }
00420 
00421 void linearrgb_to_srgb_rgba_buf(float *col, int tot)
00422 {
00423         while(tot--) {
00424                 linearrgb_to_srgb_v3_v3(col, col);
00425                 col += 4;
00426         }
00427 }
00428 
00429 void srgb_to_linearrgb_rgba_rgba_buf(float *col_to, float *col_from, int tot)
00430 {
00431         while(tot--) {
00432                 srgb_to_linearrgb_v3_v3(col_to, col_from);
00433                 col_to[3]= col_from[3];
00434                 col_to += 4;
00435                 col_from += 4;
00436         }
00437 }
00438 
00439 void linearrgb_to_srgb_rgba_rgba_buf(float *col_to, float *col_from, int tot)
00440 {
00441         while(tot--) {
00442                 linearrgb_to_srgb_v3_v3(col_to, col_from);
00443                 col_to[3]= col_from[3];
00444                 col_to += 4;
00445                 col_from += 4;
00446         }
00447 }
00448 
00449 void minmax_rgb(short c[])
00450 {
00451         if(c[0]>255) c[0]=255;
00452         else if(c[0]<0) c[0]=0;
00453         if(c[1]>255) c[1]=255;
00454         else if(c[1]<0) c[1]=0;
00455         if(c[2]>255) c[2]=255;
00456         else if(c[2]<0) c[2]=0;
00457 }
00458 
00459 /*If the requested RGB shade contains a negative weight for
00460   one of the primaries, it lies outside the color gamut 
00461   accessible from the given triple of primaries.  Desaturate
00462   it by adding white, equal quantities of R, G, and B, enough
00463   to make RGB all positive.  The function returns 1 if the
00464   components were modified, zero otherwise.*/
00465 int constrain_rgb(float *r, float *g, float *b)
00466 {
00467         float w;
00468 
00469         /* Amount of white needed is w = - min(0, *r, *g, *b) */
00470 
00471         w = (0 < *r) ? 0 : *r;
00472         w = (w < *g) ? w : *g;
00473         w = (w < *b) ? w : *b;
00474         w = -w;
00475 
00476         /* Add just enough white to make r, g, b all positive. */
00477 
00478         if (w > 0) {
00479                 *r += w;  *g += w; *b += w;
00480                 return 1;                     /* Color modified to fit RGB gamut */
00481         }
00482 
00483         return 0;                         /* Color within RGB gamut */
00484 }
00485 
00486 float rgb_to_grayscale(float rgb[3])
00487 {
00488         return 0.3f*rgb[0] + 0.58f*rgb[1] + 0.12f*rgb[2];
00489 }
00490 
00491 unsigned char rgb_to_grayscale_byte(unsigned char rgb[3])
00492 {
00493         return (76*(unsigned short)rgb[0] + 148*(unsigned short)rgb[1] + 31*(unsigned short)rgb[2]) / 255;
00494 }
00495 
00496 /* ********************************* lift/gamma/gain / ASC-CDL conversion ********************************* */
00497 
00498 void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power)
00499 {
00500         int c;
00501         for(c=0; c<3; c++) {
00502                 offset[c]= lift[c]*gain[c];
00503                 slope[c]=  gain[c]*(1.0f-lift[c]);
00504                 if(gamma[c] == 0)
00505                         power[c]= FLT_MAX;
00506                 else
00507                         power[c]= 1.0f/gamma[c];
00508         }
00509 }
00510 
00511 /* ******************************************** other ************************************************* */
00512 
00513 /* Applies an hue offset to a float rgb color */
00514 void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
00515 {
00516         float hsv[3];
00517         
00518         rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
00519         
00520         hsv[0]+= hue_offset;
00521         if(hsv[0] > 1.0f)               hsv[0] -= 1.0f;
00522         else if(hsv[0] < 0.0f)  hsv[0] += 1.0f;
00523         
00524         hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
00525 }
00526 
00527 /* Applies an hue offset to a byte rgb color */
00528 void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
00529 {
00530         float rgb_float[3];
00531         
00532         rgb_byte_to_float(rgb, rgb_float);
00533         rgb_float_set_hue_float_offset(rgb_float, hue_offset);
00534         rgb_float_to_byte(rgb_float, rgb);
00535 }