1/* This file is part of the KDE project
2 SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
3 SPDX-FileCopyrightText: 2007 Olaf Schmidt <ojschmidt@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7#include "kcolorspaces_p.h"
8#include "kguiaddons_colorhelpers_p.h"
9
10#include <QColor>
11
12#include <math.h>
13
14using namespace KColorSpaces;
15
16static inline qreal wrap(qreal a, qreal d = 1.0)
17{
18 qreal r = fmod(a, d);
19 return (r < 0.0 ? d + r : (r > 0.0 ? r : 0.0));
20}
21
22///////////////////////////////////////////////////////////////////////////////
23// HCY color space
24
25#define HCY_REC 709 // use 709 for now
26#if HCY_REC == 601
27static const qreal yc[3] = {0.299, 0.587, 0.114};
28#elif HCY_REC == 709
29static const qreal yc[3] = {0.2126, 0.7152, 0.0722};
30#else // use Qt values
31static const qreal yc[3] = {0.34375, 0.5, 0.15625};
32#endif
33
34qreal KHCY::gamma(qreal n)
35{
36 return pow(normalize(n), 2.2);
37}
38
39qreal KHCY::igamma(qreal n)
40{
41 return pow(normalize(n), 1.0 / 2.2);
42}
43
44qreal KHCY::lumag(qreal r, qreal g, qreal b)
45{
46 return r * yc[0] + g * yc[1] + b * yc[2];
47}
48
49KHCY::KHCY(qreal h_, qreal c_, qreal y_, qreal a_)
50{
51 h = h_;
52 c = c_;
53 y = y_;
54 a = a_;
55}
56
57KHCY::KHCY(const QColor &color)
58{
59 qreal r = gamma(color.redF());
60 qreal g = gamma(color.greenF());
61 qreal b = gamma(color.blueF());
62 a = color.alphaF();
63
64 // luma component
65 y = lumag(r, g, b);
66
67 // hue component
68 qreal p = qMax(qMax(r, g), b);
69 qreal n = qMin(qMin(r, g), b);
70 qreal d = 6.0 * (p - n);
71 if (n == p) {
72 h = 0.0;
73 } else if (r == p) {
74 h = ((g - b) / d);
75 } else if (g == p) {
76 h = ((b - r) / d) + (1.0 / 3.0);
77 } else {
78 h = ((r - g) / d) + (2.0 / 3.0);
79 }
80
81 // chroma component
82 if (r == g && g == b) {
83 c = 0.0;
84 } else {
85 c = qMax((y - n) / y, (p - y) / (1 - y));
86 }
87}
88
89QColor KHCY::qColor() const
90{
91 // start with sane component values
92 qreal _h = wrap(h);
93 qreal _c = normalize(c);
94 qreal _y = normalize(y);
95
96 // calculate some needed variables
97 qreal _hs = _h * 6.0;
98 qreal th;
99 qreal tm;
100 if (_hs < 1.0) {
101 th = _hs;
102 tm = yc[0] + yc[1] * th;
103 } else if (_hs < 2.0) {
104 th = 2.0 - _hs;
105 tm = yc[1] + yc[0] * th;
106 } else if (_hs < 3.0) {
107 th = _hs - 2.0;
108 tm = yc[1] + yc[2] * th;
109 } else if (_hs < 4.0) {
110 th = 4.0 - _hs;
111 tm = yc[2] + yc[1] * th;
112 } else if (_hs < 5.0) {
113 th = _hs - 4.0;
114 tm = yc[2] + yc[0] * th;
115 } else {
116 th = 6.0 - _hs;
117 tm = yc[0] + yc[2] * th;
118 }
119
120 // calculate RGB channels in sorted order
121 qreal tn;
122 qreal to;
123 qreal tp;
124 if (tm >= _y) {
125 tp = _y + _y * _c * (1.0 - tm) / tm;
126 to = _y + _y * _c * (th - tm) / tm;
127 tn = _y - (_y * _c);
128 } else {
129 tp = _y + (1.0 - _y) * _c;
130 to = _y + (1.0 - _y) * _c * (th - tm) / (1.0 - tm);
131 tn = _y - (1.0 - _y) * _c * tm / (1.0 - tm);
132 }
133
134 // return RGB channels in appropriate order
135 if (_hs < 1.0) {
136 return QColor::fromRgbF(igamma(tp), igamma(to), igamma(tn), a);
137 } else if (_hs < 2.0) {
138 return QColor::fromRgbF(igamma(to), igamma(tp), igamma(tn), a);
139 } else if (_hs < 3.0) {
140 return QColor::fromRgbF(igamma(tn), igamma(tp), igamma(to), a);
141 } else if (_hs < 4.0) {
142 return QColor::fromRgbF(igamma(tn), igamma(to), igamma(tp), a);
143 } else if (_hs < 5.0) {
144 return QColor::fromRgbF(igamma(to), igamma(tn), igamma(tp), a);
145 } else {
146 return QColor::fromRgbF(igamma(tp), igamma(tn), igamma(to), a);
147 }
148}
149
150qreal KHCY::hue(const QColor &color)
151{
152 return wrap(KHCY(color).h);
153}
154
155qreal KHCY::chroma(const QColor &color)
156{
157 return KHCY(color).c;
158}
159
160qreal KHCY::luma(const QColor &color)
161{
162 return lumag(gamma(color.redF()), gamma(color.greenF()), gamma(color.blueF()));
163}
164

source code of kguiaddons/src/colors/kcolorspaces.cpp