File indexing completed on 2024-05-19 16:50:18
0001 /***************************************************************************** 0002 * Copyright 2009 - 2010 Craig Drummond <craig.p.drummond@gmail.com> * 0003 * Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU Lesser General Public License as * 0007 * published by the Free Software Foundation; either version 2.1 of the * 0008 * License, or (at your option) version 3, or any later version accepted * 0009 * by the membership of KDE e.V. (or its successor approved by the * 0010 * membership of KDE e.V.), which shall act as a proxy defined in * 0011 * Section 6 of version 3 of the license. * 0012 * * 0013 * This program is distributed in the hope that it will be useful, * 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0016 * Lesser General Public License for more details. * 0017 * * 0018 * You should have received a copy of the GNU Lesser General Public * 0019 * License along with this library. If not, * 0020 * see <http://www.gnu.org/licenses/>. * 0021 *****************************************************************************/ 0022 0023 #ifndef QTC_UTILS_COLOR_H 0024 #define QTC_UTILS_COLOR_H 0025 0026 #include "utils.h" 0027 #include "options.h" 0028 0029 // Using c99 function in c++ mode seems to cause trouble on some OSX versions. 0030 #include <cmath> 0031 0032 typedef struct { 0033 double red; 0034 double green; 0035 double blue; 0036 } QtcColor; 0037 0038 typedef struct { 0039 double h; 0040 double c; 0041 double y; 0042 } QtcColorHCY; 0043 0044 extern double qtc_ring_alpha[3]; 0045 0046 // use 709 for now 0047 #define HCY_REC 709 0048 #if HCY_REC == 601 0049 static const double _qtc_yc[3] = {0.299, 0.587, 0.114}; 0050 #elif HCY_REC == 709 0051 static const double _qtc_yc[3] = {0.2126, 0.7152, 0.0722}; 0052 #else // use Qt values 0053 static const double _qtc_yc[3] = {0.34375, 0.5, 0.15625}; 0054 #endif 0055 #undef HCY_REC 0056 0057 QTC_ALWAYS_INLINE static inline double 0058 qtcColorWrap(double a, double d) 0059 { 0060 double r = fmod(a, d); 0061 return (r < 0.0 ? d + r : (r > 0.0 ? r : 0.0)); 0062 } 0063 0064 QTC_ALWAYS_INLINE static inline double 0065 qtcColorMixF(double a, double b, double bias) 0066 { 0067 return a + (b - a) * bias; 0068 } 0069 0070 QTC_ALWAYS_INLINE static inline double 0071 qtcColorHCYGamma(double n) 0072 { 0073 return pow(qtcBound(0, n, 1), 2.2); 0074 } 0075 0076 QTC_ALWAYS_INLINE static inline double 0077 qtcColorHCYIGamma(double n) 0078 { 0079 return pow(qtcBound(0, n, 1), 1.0 / 2.2); 0080 } 0081 0082 QTC_ALWAYS_INLINE static inline double 0083 qtcColorHCYLumag(double r, double g, double b) 0084 { 0085 return r * _qtc_yc[0] + g * _qtc_yc[1] + b * _qtc_yc[2]; 0086 } 0087 0088 QTC_ALWAYS_INLINE static inline void 0089 qtcColorFill(QtcColor *color, double r, double g, double b) 0090 { 0091 color->red = r; 0092 color->green = g; 0093 color->blue = b; 0094 } 0095 0096 QTC_ALWAYS_INLINE static inline double 0097 qtcColorHCYLuma(const QtcColor *color) 0098 { 0099 return qtcColorHCYLumag(qtcColorHCYGamma(color->red), 0100 qtcColorHCYGamma(color->green), 0101 qtcColorHCYGamma(color->blue)); 0102 } 0103 0104 static inline void 0105 qtcHsvToRgb(double *r, double *g, double *b, double h, double s, double v) 0106 { 0107 if (0 == s) { 0108 *r = *g = *b = v; 0109 } else { 0110 int i; 0111 double f; 0112 double p; 0113 0114 h /= 60; /* sector 0 to 5 */ 0115 i = (int)floor(h); 0116 f = h - i; /* factorial part of h */ 0117 p = v * (1 - s); 0118 switch (i) { 0119 case 0: 0120 *r = v; 0121 *g = v * (1 - s * (1 - f)); 0122 *b = p; 0123 break; 0124 case 1: 0125 *r = v * (1 - s * f); 0126 *g = v; 0127 *b = p; 0128 break; 0129 case 2: 0130 *r = p; 0131 *g = v; 0132 *b = v * (1 - s * (1 - f)); 0133 break; 0134 case 3: 0135 *r = p; 0136 *g = v * (1 - s * f); 0137 *b = v; 0138 break; 0139 case 4: 0140 *r = v * (1 - s * (1 - f)); 0141 *g = p; 0142 *b = v; 0143 break; 0144 case 5: 0145 default: 0146 *r = v; 0147 *g = p; 0148 *b = v * (1 - s * f); 0149 break; 0150 } 0151 } 0152 } 0153 0154 static inline void 0155 qtcRgbToHsv(double r, double g, double b, double *h, double *s, double *v) 0156 { 0157 double min = qtcMin(qtcMin(r, g), b); 0158 double max = qtcMax(qtcMax(r, g), b); 0159 double delta = max - min; 0160 0161 *v = max; 0162 if (max != 0) { 0163 *s = delta / max; 0164 } else { 0165 *s = 0; 0166 } 0167 0168 if (*s == 0.0) { 0169 *h = 0.0; 0170 } else { 0171 if (r == max) { 0172 *h = (g - b) / delta; /* between yellow & magenta */ 0173 } else if (g == max) { 0174 *h = 2 + (b - r) / delta; /* between cyan & yellow */ 0175 } else { 0176 *h = 4 + (r - g) / delta; /* between magenta & cyan */ 0177 } 0178 *h *= 60; /* degrees */ 0179 if (*h < 0) { 0180 *h += 360; 0181 } 0182 } 0183 } 0184 0185 void _qtcColorLighten(QtcColor *color, double ky, double kc); 0186 void _qtcColorDarken(QtcColor *color, double ky, double kc); 0187 void _qtcColorShade(QtcColor *color, double ky, double kc); 0188 void _qtcColorTint(const QtcColor *base, const QtcColor *col, 0189 double amount, QtcColor *out); 0190 void _qtcColorMix(const QtcColor *c1, const QtcColor *c2, 0191 double bias, QtcColor *out); 0192 void _qtcShade(const QtcColor *ca, QtcColor *cb, double k, Shading shading); 0193 double _qtcShineAlpha(const QtcColor *bgnd); 0194 void _qtcCalcRingAlphas(const QtcColor *bgnd); 0195 void qtcColorFromStr(QtcColor *color, const char *str); 0196 void qtcColorToStr(const QtcColor *color, char *str); 0197 0198 typedef enum { 0199 QTC_PIXEL_ARGB, 0200 QTC_PIXEL_BGRA, 0201 QTC_PIXEL_RGBA, 0202 QTC_PIXEL_GDK = QTC_PIXEL_RGBA, 0203 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 0204 QTC_PIXEL_XCB = QTC_PIXEL_ARGB, 0205 QTC_PIXEL_QT = QTC_PIXEL_ARGB, 0206 #else 0207 QTC_PIXEL_XCB = QTC_PIXEL_BGRA, 0208 QTC_PIXEL_QT = QTC_PIXEL_BGRA, 0209 #endif 0210 } QtcPixelByteOrder; 0211 void qtcAdjustPix(unsigned char *data, int numChannels, int w, int h, 0212 int stride, int ro, int go, int bo, double shade, 0213 QtcPixelByteOrder byte_order); 0214 0215 #ifndef QTC_UTILS_INTERNAL 0216 0217 #ifdef QTC_UTILS_QT 0218 #include <QColor> 0219 0220 QTC_ALWAYS_INLINE static inline QColor 0221 qtcColorLighten(const QColor *color, double ky, double kc) 0222 { 0223 QtcColor qtc_color = {color->redF(), color->greenF(), color->blueF()}; 0224 _qtcColorLighten(&qtc_color, ky, kc); 0225 return QColor::fromRgbF(qtc_color.red, qtc_color.green, qtc_color.blue); 0226 } 0227 0228 QTC_ALWAYS_INLINE static inline QColor 0229 qtcColorDarken(const QColor *color, double ky, double kc) 0230 { 0231 QtcColor qtc_color = {color->redF(), color->greenF(), color->blueF()}; 0232 _qtcColorDarken(&qtc_color, ky, kc); 0233 return QColor::fromRgbF(qtc_color.red, qtc_color.green, qtc_color.blue); 0234 } 0235 0236 QTC_ALWAYS_INLINE static inline QColor 0237 qtcColorShade(const QColor *color, double ky, double kc) 0238 { 0239 QtcColor qtc_color = {color->redF(), color->greenF(), color->blueF()}; 0240 _qtcColorShade(&qtc_color, ky, kc); 0241 return QColor::fromRgbF(qtc_color.red, qtc_color.green, qtc_color.blue); 0242 } 0243 0244 QTC_ALWAYS_INLINE static inline QColor 0245 qtcColorTint(const QColor *base, const QColor *col, double amount) 0246 { 0247 if (amount <= 0.0) { 0248 return *base; 0249 } else if (amount >= 1.0) { 0250 return *col; 0251 } else if (std::isnan(amount)) { 0252 return *base; 0253 } 0254 const QtcColor qtc_base = {base->redF(), base->greenF(), base->blueF()}; 0255 const QtcColor qtc_col = {col->redF(), col->greenF(), col->blueF()}; 0256 QtcColor out; 0257 _qtcColorTint(&qtc_base, &qtc_col, amount, &out); 0258 return QColor::fromRgbF(out.red, out.green, out.blue); 0259 } 0260 0261 QTC_ALWAYS_INLINE static inline QColor 0262 qtcColorMix(const QColor *c1, const QColor *c2, double bias) 0263 { 0264 if (bias <= 0.0) { 0265 return *c1; 0266 } else if (bias >= 1.0) { 0267 return *c2; 0268 } else if (std::isnan(bias)) { 0269 return *c1; 0270 } 0271 const QtcColor qtc_c1 = {c1->redF(), c1->greenF(), c1->blueF()}; 0272 const QtcColor qtc_c2 = {c2->redF(), c2->greenF(), c2->blueF()}; 0273 QtcColor out; 0274 _qtcColorMix(&qtc_c1, &qtc_c2, bias, &out); 0275 return QColor::fromRgbF(out.red, out.green, out.blue); 0276 } 0277 0278 QTC_ALWAYS_INLINE static inline double 0279 qtcColorLuma(const QColor *color) 0280 { 0281 QtcColor qtc_color = {color->redF(), color->greenF(), color->blueF()}; 0282 return qtcColorHCYLuma(&qtc_color); 0283 } 0284 0285 QTC_ALWAYS_INLINE static inline void 0286 qtcShade(const QColor *ca, QColor *cb, double k, Shading shading) 0287 { 0288 if (qtcEqual(k, 1.0)) { 0289 *cb = *ca; 0290 return; 0291 } 0292 const QtcColor qtc_ca = {ca->redF(), ca->greenF(), ca->blueF()}; 0293 QtcColor qtc_cb; 0294 _qtcShade(&qtc_ca, &qtc_cb, k, shading); 0295 cb->setRgbF(qtc_cb.red, qtc_cb.green, qtc_cb.blue, ca->alphaF()); 0296 } 0297 0298 QTC_ALWAYS_INLINE static inline double 0299 qtcShineAlpha(const QColor *bgnd) 0300 { 0301 const QtcColor qtc_bgnd = {bgnd->redF(), bgnd->greenF(), bgnd->blueF()}; 0302 return _qtcShineAlpha(&qtc_bgnd); 0303 } 0304 0305 QTC_ALWAYS_INLINE static inline void 0306 qtcCalcRingAlphas(const QColor *bgnd) 0307 { 0308 const QtcColor qtc_bgnd = {bgnd->redF(), bgnd->greenF(), bgnd->blueF()}; 0309 _qtcCalcRingAlphas(&qtc_bgnd); 0310 } 0311 #endif 0312 0313 #ifdef QTC_UTILS_GTK 0314 #include <gdk/gdk.h> 0315 0316 QTC_ALWAYS_INLINE static inline GdkColor 0317 _qtcColorToGdk(const QtcColor *qtc_color) 0318 { 0319 GdkColor color; 0320 color.red = qtc_color->red * 65535; 0321 color.green = qtc_color->green * 65535; 0322 color.blue = qtc_color->blue * 65535; 0323 return color; 0324 } 0325 0326 QTC_ALWAYS_INLINE static inline QtcColor 0327 _qtc_color_from_gdk(const GdkColor *color) 0328 { 0329 QtcColor qtc_color; 0330 qtc_color.red = color->red / 65535.0; 0331 qtc_color.green = color->green / 65535.0; 0332 qtc_color.blue = color->blue / 65535.0; 0333 return qtc_color; 0334 } 0335 0336 QTC_ALWAYS_INLINE static inline GdkColor 0337 qtcColorLighten(const GdkColor *color, double ky, double kc) 0338 { 0339 QtcColor qtc_color = _qtc_color_from_gdk(color); 0340 _qtcColorLighten(&qtc_color, ky, kc); 0341 return _qtcColorToGdk(&qtc_color); 0342 } 0343 0344 QTC_ALWAYS_INLINE static inline GdkColor 0345 qtcColorDarken(const GdkColor *color, double ky, double kc) 0346 { 0347 QtcColor qtc_color = _qtc_color_from_gdk(color); 0348 _qtcColorDarken(&qtc_color, ky, kc); 0349 return _qtcColorToGdk(&qtc_color); 0350 } 0351 0352 QTC_ALWAYS_INLINE static inline GdkColor 0353 qtcColorShade(const GdkColor *color, double ky, double kc) 0354 { 0355 QtcColor qtc_color = _qtc_color_from_gdk(color); 0356 _qtcColorShade(&qtc_color, ky, kc); 0357 return _qtcColorToGdk(&qtc_color); 0358 } 0359 0360 QTC_ALWAYS_INLINE static inline GdkColor 0361 qtcColorTint(const GdkColor *base, const GdkColor *col, double amount) 0362 { 0363 if (amount <= 0.0) { 0364 return *base; 0365 } else if (amount >= 1.0) { 0366 return *col; 0367 } else if (std::isnan(amount)) { 0368 return *base; 0369 } 0370 QtcColor qtc_base = _qtc_color_from_gdk(base); 0371 QtcColor qtc_col = _qtc_color_from_gdk(col); 0372 QtcColor out; 0373 _qtcColorTint(&qtc_base, &qtc_col, amount, &out); 0374 return _qtcColorToGdk(&out); 0375 } 0376 0377 QTC_ALWAYS_INLINE static inline GdkColor 0378 qtcColorMix(const GdkColor *c1, const GdkColor *c2, double bias) 0379 { 0380 if (bias <= 0.0) { 0381 return *c1; 0382 } else if (bias >= 1.0) { 0383 return *c2; 0384 } else if (std::isnan(bias)) { 0385 return *c1; 0386 } 0387 QtcColor qtc_c1 = _qtc_color_from_gdk(c1); 0388 QtcColor qtc_c2 = _qtc_color_from_gdk(c2); 0389 QtcColor out; 0390 _qtcColorMix(&qtc_c1, &qtc_c2, bias, &out); 0391 return _qtcColorToGdk(&out); 0392 } 0393 0394 QTC_ALWAYS_INLINE static inline double 0395 qtcColorLuma(const GdkColor *color) 0396 { 0397 QtcColor qtc_color = _qtc_color_from_gdk(color); 0398 return qtcColorHCYLuma(&qtc_color); 0399 } 0400 0401 QTC_ALWAYS_INLINE static inline void 0402 qtcShade(const GdkColor *ca, GdkColor *cb, double k, Shading shading) 0403 { 0404 if (qtcEqual(k, 1.0)) { 0405 *cb = *ca; 0406 return; 0407 } 0408 QtcColor qtc_ca = _qtc_color_from_gdk(ca); 0409 QtcColor qtc_cb; 0410 _qtcShade(&qtc_ca, &qtc_cb, k, shading); 0411 *cb = _qtcColorToGdk(&qtc_cb); 0412 } 0413 0414 QTC_ALWAYS_INLINE static inline double 0415 qtcShineAlpha(const GdkColor *bgnd) 0416 { 0417 QtcColor qtc_bgnd = _qtc_color_from_gdk(bgnd); 0418 return _qtcShineAlpha(&qtc_bgnd); 0419 } 0420 0421 QTC_ALWAYS_INLINE static inline void 0422 qtcCalcRingAlphas(const GdkColor *bgnd) 0423 { 0424 QtcColor qtc_bgnd = _qtc_color_from_gdk(bgnd); 0425 _qtcCalcRingAlphas(&qtc_bgnd); 0426 } 0427 0428 #endif 0429 0430 namespace QtCurve { 0431 0432 #ifdef QTC_UTILS_QT 0433 0434 static inline bool 0435 isBlack(const QColor &color) 0436 { 0437 return color.red() == 0 && color.green() == 0 && color.blue() == 0; 0438 } 0439 0440 #endif 0441 0442 #ifdef QTC_UTILS_GTK 0443 0444 static inline bool 0445 isBlack(const GdkColor &color) 0446 { 0447 return color.red == 0 && color.green == 0 && color.blue == 0; 0448 } 0449 0450 #endif 0451 0452 } 0453 0454 #endif 0455 0456 #endif