File indexing completed on 2024-12-08 06:39:04

0001 /*  This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2007 Olaf Schmidt <ojschmidt@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 #include "kcolorspaces_p.h"
0008 #include "kguiaddons_colorhelpers_p.h"
0009 
0010 #include <QColor>
0011 
0012 #include <math.h>
0013 
0014 using namespace KColorSpaces;
0015 
0016 static inline qreal wrap(qreal a, qreal d = 1.0)
0017 {
0018     qreal r = fmod(a, d);
0019     return (r < 0.0 ? d + r : (r > 0.0 ? r : 0.0));
0020 }
0021 
0022 ///////////////////////////////////////////////////////////////////////////////
0023 // HCY color space
0024 
0025 #define HCY_REC 709 // use 709 for now
0026 #if HCY_REC == 601
0027 static const qreal yc[3] = {0.299, 0.587, 0.114};
0028 #elif HCY_REC == 709
0029 static const qreal yc[3] = {0.2126, 0.7152, 0.0722};
0030 #else // use Qt values
0031 static const qreal yc[3] = {0.34375, 0.5, 0.15625};
0032 #endif
0033 
0034 qreal KHCY::gamma(qreal n)
0035 {
0036     return pow(normalize(n), 2.2);
0037 }
0038 
0039 qreal KHCY::igamma(qreal n)
0040 {
0041     return pow(normalize(n), 1.0 / 2.2);
0042 }
0043 
0044 qreal KHCY::lumag(qreal r, qreal g, qreal b)
0045 {
0046     return r * yc[0] + g * yc[1] + b * yc[2];
0047 }
0048 
0049 KHCY::KHCY(qreal h_, qreal c_, qreal y_, qreal a_)
0050 {
0051     h = h_;
0052     c = c_;
0053     y = y_;
0054     a = a_;
0055 }
0056 
0057 KHCY::KHCY(const QColor &color)
0058 {
0059     qreal r = gamma(color.redF());
0060     qreal g = gamma(color.greenF());
0061     qreal b = gamma(color.blueF());
0062     a = color.alphaF();
0063 
0064     // luma component
0065     y = lumag(r, g, b);
0066 
0067     // hue component
0068     qreal p = qMax(qMax(r, g), b);
0069     qreal n = qMin(qMin(r, g), b);
0070     qreal d = 6.0 * (p - n);
0071     if (n == p) {
0072         h = 0.0;
0073     } else if (r == p) {
0074         h = ((g - b) / d);
0075     } else if (g == p) {
0076         h = ((b - r) / d) + (1.0 / 3.0);
0077     } else {
0078         h = ((r - g) / d) + (2.0 / 3.0);
0079     }
0080 
0081     // chroma component
0082     if (r == g && g == b) {
0083         c = 0.0;
0084     } else {
0085         c = qMax((y - n) / y, (p - y) / (1 - y));
0086     }
0087 }
0088 
0089 QColor KHCY::qColor() const
0090 {
0091     // start with sane component values
0092     qreal _h = wrap(h);
0093     qreal _c = normalize(c);
0094     qreal _y = normalize(y);
0095 
0096     // calculate some needed variables
0097     qreal _hs = _h * 6.0;
0098     qreal th;
0099     qreal tm;
0100     if (_hs < 1.0) {
0101         th = _hs;
0102         tm = yc[0] + yc[1] * th;
0103     } else if (_hs < 2.0) {
0104         th = 2.0 - _hs;
0105         tm = yc[1] + yc[0] * th;
0106     } else if (_hs < 3.0) {
0107         th = _hs - 2.0;
0108         tm = yc[1] + yc[2] * th;
0109     } else if (_hs < 4.0) {
0110         th = 4.0 - _hs;
0111         tm = yc[2] + yc[1] * th;
0112     } else if (_hs < 5.0) {
0113         th = _hs - 4.0;
0114         tm = yc[2] + yc[0] * th;
0115     } else {
0116         th = 6.0 - _hs;
0117         tm = yc[0] + yc[2] * th;
0118     }
0119 
0120     // calculate RGB channels in sorted order
0121     qreal tn;
0122     qreal to;
0123     qreal tp;
0124     if (tm >= _y) {
0125         tp = _y + _y * _c * (1.0 - tm) / tm;
0126         to = _y + _y * _c * (th - tm) / tm;
0127         tn = _y - (_y * _c);
0128     } else {
0129         tp = _y + (1.0 - _y) * _c;
0130         to = _y + (1.0 - _y) * _c * (th - tm) / (1.0 - tm);
0131         tn = _y - (1.0 - _y) * _c * tm / (1.0 - tm);
0132     }
0133 
0134     // return RGB channels in appropriate order
0135     if (_hs < 1.0) {
0136         return QColor::fromRgbF(igamma(tp), igamma(to), igamma(tn), a);
0137     } else if (_hs < 2.0) {
0138         return QColor::fromRgbF(igamma(to), igamma(tp), igamma(tn), a);
0139     } else if (_hs < 3.0) {
0140         return QColor::fromRgbF(igamma(tn), igamma(tp), igamma(to), a);
0141     } else if (_hs < 4.0) {
0142         return QColor::fromRgbF(igamma(tn), igamma(to), igamma(tp), a);
0143     } else if (_hs < 5.0) {
0144         return QColor::fromRgbF(igamma(to), igamma(tn), igamma(tp), a);
0145     } else {
0146         return QColor::fromRgbF(igamma(tp), igamma(tn), igamma(to), a);
0147     }
0148 }
0149 
0150 qreal KHCY::hue(const QColor &color)
0151 {
0152     return wrap(KHCY(color).h);
0153 }
0154 
0155 qreal KHCY::chroma(const QColor &color)
0156 {
0157     return KHCY(color).c;
0158 }
0159 
0160 qreal KHCY::luma(const QColor &color)
0161 {
0162     return lumag(gamma(color.redF()), gamma(color.greenF()), gamma(color.blueF()));
0163 }