/* This file is taken from kcolorspaces.cpp and kcolorutils.cpp from tdelibs The code has been modified to work with TQColor (TQt3 &TQt4) and GdkColor */ /* This file is part of the KDE project * Copyright (C) 2007 Matthew Woehlke * Copyright (C) 2007 Olaf Schmidt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #ifdef __cplusplus #if (0x039999 >= 0x040000) #define FLOAT_COLOR(VAL, COL) (VAL).COL##F() #define TO_COLOR(R, G, B) TQColor::fromRgbF(R, G, B) #else #define FLOAT_COLOR(VAL, COL) ((double)(((VAL).COL()*1.0)/255.0)) #define TO_COLOR(R, G, B) TQColor(limit(R*255.0), limit(G*255.0), limit(B*255.0)) #endif #else #define inline #define FLOAT_COLOR(VAL, COL) ((double)(((VAL).COL*1.0)/65535.0)) static GdkColor qtcGdkColor(double r, double g, double b) { GdkColor col; col.red=limit(r*65535); col.green=limit(g*65535); col.blue=limit(b*65535); return col; } #define TO_COLOR(R, G, B) qtcGdkColor(R, G, B) #endif static inline double ColorUtils_normalize(double a) { return (a < 1.0 ? (a > 0.0 ? a : 0.0) : 1.0); } static inline double ColorUtils_wrap(double a) { static double d = 1.0; double r = fmod(a, d); return (r < 0.0 ? d + r : (r > 0.0 ? r : 0.0)); } #define HCY_REC 709 // use 709 for now #if HCY_REC == 601 static const double yc[3] = { 0.299, 0.587, 0.114 }; #elif HCY_REC == 709 static const double yc[3] = {0.2126, 0.7152, 0.0722}; #else // use TQt values static const double yc[3] = { 0.34375, 0.5, 0.15625 }; #endif static inline double ColorUtils_HCY_gamma(double n) { return pow(ColorUtils_normalize(n), 2.2); } static inline double ColorUtils_HCY_igamma(double n) { return pow(ColorUtils_normalize(n), 1.0/2.2); } static inline double ColorUtils_HCY_lumag(double r, double g, double b) { return r*yc[0] + g*yc[1] + b*yc[2]; } typedef struct { double h, c, y; } ColorUtils_HCY; // static ColorUtils_HCY ColorUtils_HCY_fromValues(double h_, double c_, double y_/*, double a_*/) // { // h = h_; // c = c_; // y = y_; // // a = a_; // } static ColorUtils_HCY ColorUtils_HCY_fromColor(const color *color) { ColorUtils_HCY hcy; double r = ColorUtils_HCY_gamma(FLOAT_COLOR(*color, red)); double g = ColorUtils_HCY_gamma(FLOAT_COLOR(*color, green)); double b = ColorUtils_HCY_gamma(FLOAT_COLOR(*color, blue)); // a = color.alphaF(); // luma component hcy.y = ColorUtils_HCY_lumag(r, g, b); // hue component double p = MAX(MAX(r, g), b); double n = MIN(MIN(r, g), b); double d = 6.0 * (p - n); if (n == p) hcy.h = 0.0; else if (r == p) hcy.h = ((g - b) / d); else if (g == p) hcy.h = ((b - r) / d) + (1.0 / 3.0); else hcy.h = ((r - g) / d) + (2.0 / 3.0); // chroma component if (0.0 == hcy.y || 1.0 == hcy.y) hcy.c = 0.0; else hcy.c = MAX( (hcy.y - n) / hcy.y, (p - hcy.y) / (1 - hcy.y) ); return hcy; } static color ColorUtils_HCY_toColor(ColorUtils_HCY *hcy) { // start with sane component values double _h = ColorUtils_wrap(hcy->h); double _c = ColorUtils_normalize(hcy->c); double _y = ColorUtils_normalize(hcy->y); // calculate some needed variables double _hs = _h * 6.0, th, tm; if (_hs < 1.0) { th = _hs; tm = yc[0] + yc[1] * th; } else if (_hs < 2.0) { th = 2.0 - _hs; tm = yc[1] + yc[0] * th; } else if (_hs < 3.0) { th = _hs - 2.0; tm = yc[1] + yc[2] * th; } else if (_hs < 4.0) { th = 4.0 - _hs; tm = yc[2] + yc[1] * th; } else if (_hs < 5.0) { th = _hs - 4.0; tm = yc[2] + yc[0] * th; } else { th = 6.0 - _hs; tm = yc[0] + yc[2] * th; } // calculate RGB channels in sorted order double tn, to, tp; if (tm >= _y) { tp = _y + _y * _c * (1.0 - tm) / tm; to = _y + _y * _c * (th - tm) / tm; tn = _y - (_y * _c); } else { tp = _y + (1.0 - _y) * _c; to = _y + (1.0 - _y) * _c * (th - tm) / (1.0 - tm); tn = _y - (1.0 - _y) * _c * tm / (1.0 - tm); } // return RGB channels in appropriate order if (_hs < 1.0) return TO_COLOR(ColorUtils_HCY_igamma(tp), ColorUtils_HCY_igamma(to), ColorUtils_HCY_igamma(tn)); else if (_hs < 2.0) return TO_COLOR(ColorUtils_HCY_igamma(to), ColorUtils_HCY_igamma(tp), ColorUtils_HCY_igamma(tn)); else if (_hs < 3.0) return TO_COLOR(ColorUtils_HCY_igamma(tn), ColorUtils_HCY_igamma(tp), ColorUtils_HCY_igamma(to)); else if (_hs < 4.0) return TO_COLOR(ColorUtils_HCY_igamma(tn), ColorUtils_HCY_igamma(to), ColorUtils_HCY_igamma(tp)); else if (_hs < 5.0) return TO_COLOR(ColorUtils_HCY_igamma(to), ColorUtils_HCY_igamma(tn), ColorUtils_HCY_igamma(tp)); else return TO_COLOR(ColorUtils_HCY_igamma(tp), ColorUtils_HCY_igamma(tn), ColorUtils_HCY_igamma(to)); } // #ifndef __cplusplus static inline double ColorUtils_HCY_luma(const color *color) { return ColorUtils_HCY_lumag(ColorUtils_HCY_gamma(FLOAT_COLOR(*color, red)), ColorUtils_HCY_gamma(FLOAT_COLOR(*color, green)), ColorUtils_HCY_gamma(FLOAT_COLOR(*color, blue))); } static inline double ColorUtils_mixQreal(double a, double b, double bias) { return a + (b - a) * bias; } static inline double ColorUtils_luma(const color *color) { return ColorUtils_HCY_luma(color); } static double ColorUtils_contrastRatio(const color *c1, const color *c2) { double y1 = ColorUtils_luma(c1), y2 = ColorUtils_luma(c2); if (y1 > y2) return (y1 + 0.05) / (y2 + 0.05); else return (y2 + 0.05) / (y1 + 0.05); } static color ColorUtils_lighten(const color *color, double ky, double kc) { ColorUtils_HCY c=ColorUtils_HCY_fromColor(color); c.y = 1.0 - ColorUtils_normalize((1.0 - c.y) * (1.0 - ky)); c.c = 1.0 - ColorUtils_normalize((1.0 - c.c) * kc); return ColorUtils_HCY_toColor(&c); } static color ColorUtils_darken(const color *color, double ky, double kc) { ColorUtils_HCY c=ColorUtils_HCY_fromColor(color); c.y = ColorUtils_normalize(c.y * (1.0 - ky)); c.c = ColorUtils_normalize(c.c * kc); return ColorUtils_HCY_toColor(&c); } static color ColorUtils_shade(const color *color, double ky, double kc) { ColorUtils_HCY c=ColorUtils_HCY_fromColor(color); c.y = ColorUtils_normalize(c.y + ky); c.c = ColorUtils_normalize(c.c + kc); return ColorUtils_HCY_toColor(&c); } static color ColorUtils_mix(const color *c1, const color *c2, double bias); static color ColorUtils_tintHelper(const color *base, const color *col, double amount) { color mixed=ColorUtils_mix(base, col, pow(amount, 0.3)); ColorUtils_HCY c=ColorUtils_HCY_fromColor(&mixed); c.y = ColorUtils_mixQreal(ColorUtils_luma(base), c.y, amount); return ColorUtils_HCY_toColor(&c); } static color ColorUtils_tint(const color *base, const color *col, double amount) { if (amount <= 0.0) return *base; if (amount >= 1.0) return *col; if (isnan(amount)) return *base; double ri = ColorUtils_contrastRatio(base, col); double rg = 1.0 + ((ri + 1.0) * amount * amount * amount); double u = 1.0, l = 0.0; color result; int i; for (i = 12 ; i ; --i) { double a = 0.5 * (l+u); result = ColorUtils_tintHelper(base, col, a); double ra = ColorUtils_contrastRatio(base, &result); if (ra > rg) u = a; else l = a; } return result; } static color ColorUtils_mix(const color *c1, const color *c2, double bias) { if (bias <= 0.0) return *c1; if (bias >= 1.0) return *c2; if (isnan(bias)) return *c1; { double r = ColorUtils_mixQreal(FLOAT_COLOR(*c1, red), FLOAT_COLOR(*c2, red), bias); double g = ColorUtils_mixQreal(FLOAT_COLOR(*c1, green), FLOAT_COLOR(*c2, green), bias); double b = ColorUtils_mixQreal(FLOAT_COLOR(*c1, blue), FLOAT_COLOR(*c2, blue), bias); /*double a = ColorUtils_mixQreal(FLOAT_COLOR(*c1, alpha), FLOAT_COLOR(*c2, alpha), bias);*/ return TO_COLOR(r, g, b); } } // #endif /* Added!!! */ // static color ColorUtils_shade_qtc(const color *color, double k) // { // ColorUtils_HCY c=ColorUtils_HCY_fromColor(color); // c.y = ColorUtils_normalize(c.y * (k>1.0 ? (k*1.1) : (k<1.0 ? (k*0.9) : k))); // return ColorUtils_HCY_toColor(&c); // }