1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QCOLORTRANSFERFUNCTION_P_H
41 #define QCOLORTRANSFERFUNCTION_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtGui/private/qtguiglobal_p.h>
55 
56 #include <cmath>
57 
58 QT_BEGIN_NAMESPACE
59 
60 // Defines a ICC parametric curve type 4
61 class Q_GUI_EXPORT QColorTransferFunction
62 {
63 public:
QColorTransferFunction()64     QColorTransferFunction() noexcept
65             : m_a(1.0f), m_b(0.0f), m_c(1.0f), m_d(0.0f), m_e(0.0f), m_f(0.0f), m_g(1.0f), m_flags(0)
66     { }
QColorTransferFunction(float a,float b,float c,float d,float e,float f,float g)67     QColorTransferFunction(float a, float b, float c, float d, float e, float f, float g) noexcept
68             : m_a(a), m_b(b), m_c(c), m_d(d), m_e(e), m_f(f), m_g(g), m_flags(0)
69     { }
70 
isGamma()71     bool isGamma() const
72     {
73         updateHints();
74         return m_flags & quint32(Hints::IsGamma);
75     }
isLinear()76     bool isLinear() const
77     {
78         updateHints();
79         return m_flags & quint32(Hints::IsLinear);
80     }
isSRgb()81     bool isSRgb() const
82     {
83         updateHints();
84         return m_flags & quint32(Hints::IsSRgb);
85     }
86 
apply(float x)87     float apply(float x) const
88     {
89         if (x < m_d)
90             return m_c * x + m_f;
91         else
92             return std::pow(m_a * x + m_b, m_g) + m_e;
93     }
94 
inverted()95     QColorTransferFunction inverted() const
96     {
97         float a, b, c, d, e, f, g;
98 
99         d = m_c * m_d + m_f;
100 
101         if (!qFuzzyIsNull(m_c)) {
102             c = 1.0f / m_c;
103             f = -m_f / m_c;
104         } else {
105             c = 0.0f;
106             f = 0.0f;
107         }
108 
109         if (!qFuzzyIsNull(m_a) && !qFuzzyIsNull(m_g)) {
110             a = std::pow(1.0f / m_a, m_g);
111             b = -a * m_e;
112             e = -m_b / m_a;
113             g = 1.0f / m_g;
114         } else {
115             a = 0.0f;
116             b = 0.0f;
117             e = 1.0f;
118             g = 1.0f;
119         }
120 
121         return QColorTransferFunction(a, b, c, d, e, f, g);
122     }
123 
124     // A few predefined curves:
fromGamma(float gamma)125     static QColorTransferFunction fromGamma(float gamma)
126     {
127         return QColorTransferFunction(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, gamma);
128     }
fromSRgb()129     static QColorTransferFunction fromSRgb()
130     {
131         return QColorTransferFunction(1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045f, 0.0f, 0.0f, 2.4f);
132     }
fromProPhotoRgb()133     static QColorTransferFunction fromProPhotoRgb()
134     {
135         return QColorTransferFunction(1.0f, 0.0f, 1.0f / 16.0f, 16.0f / 512.0f, 0.0f, 0.0f, 1.8f);
136     }
matches(const QColorTransferFunction & o)137     bool matches(const QColorTransferFunction &o) const
138     {
139         return paramCompare(m_a, o.m_a) && paramCompare(m_b, o.m_b)
140             && paramCompare(m_c, o.m_c) && paramCompare(m_d, o.m_d)
141             && paramCompare(m_e, o.m_e) && paramCompare(m_f, o.m_f)
142             && paramCompare(m_g, o.m_g);
143     }
144     friend inline bool operator==(const QColorTransferFunction &f1, const QColorTransferFunction &f2);
145     friend inline bool operator!=(const QColorTransferFunction &f1, const QColorTransferFunction &f2);
146 
147     float m_a;
148     float m_b;
149     float m_c;
150     float m_d;
151     float m_e;
152     float m_f;
153     float m_g;
154 
155 private:
paramCompare(float p1,float p2)156     static inline bool paramCompare(float p1, float p2)
157     {
158         // Much fuzzier than fuzzy compare.
159         // It tries match parameters that has been passed through a 8.8
160         // fixed point form.
161         return (qAbs(p1 - p2) <= (1.0f / 512.0f));
162     }
163 
updateHints()164     void updateHints() const
165     {
166         if (m_flags & quint32(Hints::Calculated))
167             return;
168         // We do not consider the case with m_d = 1.0f linear or simple,
169         // since it wouldn't be linear for applyExtended().
170         bool simple = paramCompare(m_a, 1.0f) && paramCompare(m_b, 0.0f)
171                                               && paramCompare(m_d, 0.0f)
172                                               && paramCompare(m_e, 0.0f);
173         if (simple) {
174             m_flags |= quint32(Hints::IsGamma);
175             if (qFuzzyCompare(m_g, 1.0f))
176                 m_flags |= quint32(Hints::IsLinear);
177         } else {
178             if (*this == fromSRgb())
179                 m_flags |= quint32(Hints::IsSRgb);
180         }
181         m_flags |= quint32(Hints::Calculated);
182     }
183     enum class Hints : quint32 {
184         Calculated = 1,
185         IsGamma = 2,
186         IsLinear = 4,
187         IsSRgb = 8
188     };
189     mutable quint32 m_flags;
190 };
191 
192 inline bool operator==(const QColorTransferFunction &f1, const QColorTransferFunction &f2)
193 {
194     return f1.matches(f2);
195 }
196 inline bool operator!=(const QColorTransferFunction &f1, const QColorTransferFunction &f2)
197 {
198     return !f1.matches(f2);
199 }
200 
201 QT_END_NAMESPACE
202 
203 #endif // QCOLORTRANSFERFUNCTION_P_H
204