File indexing completed on 2024-04-28 05:46:49

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