Perceptual Color

rgbcolorspace_p.h
1// SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
2// SPDX-License-Identifier: BSD-2-Clause OR MIT
3
4#ifndef RGBCOLORSPACE_P_H
5#define RGBCOLORSPACE_P_H
6
7// Include the header of the public class of this private implementation.
8// #include "rgbcolorspace.h"
9
10#include "cielchd50values.h"
11#include "constpropagatingrawpointer.h"
12#include "helperconstants.h"
13#include "oklchvalues.h"
14#include <lcms2.h>
15#include <qcontainerfwd.h>
16#include <qdatetime.h>
17#include <qglobal.h>
18#include <qlist.h>
19#include <qmap.h>
20#include <qstring.h>
21#include <qversionnumber.h>
22
23namespace PerceptualColor
24{
25class RgbColorSpace;
26
27/** @internal
28 *
29 * @brief Private implementation within the <em>Pointer to
30 * implementation</em> idiom */
31class RgbColorSpacePrivate final
32{
33private:
34 [[nodiscard]] static QMap<cmsUInt32Number, QString> getIntentList();
35
36public:
37 explicit RgbColorSpacePrivate(RgbColorSpace *backLink);
38 /** @brief Default destructor
39 *
40 * The destructor is non-<tt>virtual</tt> because
41 * the class as a whole is <tt>final</tt>. */
42 ~RgbColorSpacePrivate() noexcept = default;
43
44 // Data members:
45 /** @brief The darkest in-gamut point on the L* axis.
46 * @sa whitepointL
47 *
48 * @internal
49 *
50 * @todo Use cmsDetectBlackPoint? But “our” “blackpoint” is always on
51 * the grey axis, but the real blackpoint not? Document this? */
52 qreal m_cielabD50BlackpointL = 0;
53 /** @brief The lightest in-gamut point on the L* axis.
54 * @sa blackpointL() */
55 qreal m_cielabD50WhitepointL = 100;
56 /** @brief The darkest in-gamut point on the L* axis.
57 * @sa whitepointL
58 *
59 * @internal
60 *
61 * @todo Use cmsDetectBlackPoint? But “our” “blackpoint” is always on
62 * the grey axis, but the real blackpoint not? Document this? */
63 qreal m_oklabBlackpointL = 0;
64 /** @brief The lightest in-gamut point on the L* axis.
65 * @sa blackpointL() */
66 qreal m_oklabWhitepointL = 1;
67 /** @brief Internal storage for property
68 * @ref RgbColorSpace::profileAbsoluteFilePath */
69 QString m_profileAbsoluteFilePath;
70 /** @brief Internal storage for property
71 * @ref RgbColorSpace::profileClass */
72 cmsProfileClassSignature m_profileClass;
73 /** @brief Internal storage for property
74 * @ref RgbColorSpace::profileColorModel */
75 cmsColorSpaceSignature m_profileColorModel;
76 /** @brief Internal storage for property
77 * @ref RgbColorSpace::profileCopyright */
78 QString m_profileCopyright;
79 /** @brief Internal storage for property
80 * @ref RgbColorSpace::profileCreationDateTime */
81 QDateTime m_profileCreationDateTime;
82 /** @brief Internal storage for property
83 * @ref RgbColorSpace::profileFileSize */
84 qint64 m_profileFileSize = -1;
85 /** @brief Internal storage for property
86 * @ref RgbColorSpace::profileHasClut */
87 bool m_profileHasClut = false;
88 /** @brief Internal storage for property
89 * @ref RgbColorSpace::profileHasMatrixShaper */
90 bool m_profileHasMatrixShaper = false;
91 /** @brief Internal storage for property
92 * @ref RgbColorSpace::profileIccVersion */
93 QVersionNumber m_profileIccVersion;
94 /** @brief Internal storage for property
95 * @ref RgbColorSpace::profileManufacturer */
96 QString m_profileManufacturer;
97 /** @brief Internal storage for property
98 * @ref RgbColorSpace::profileMaximumCielchD50Chroma */
99 double m_profileMaximumCielchD50Chroma = CielchD50Values::maximumChroma;
100 /** @brief Internal storage for property
101 * @ref RgbColorSpace::profileMaximumOklchChroma */
102 double m_profileMaximumOklchChroma = OklchValues::maximumChroma;
103 /** @brief Internal storage for property
104 * @ref RgbColorSpace::profileModel */
105 QString m_profileModel;
106 /** @brief Internal storage for property
107 * @ref RgbColorSpace::profileName */
108 QString m_profileName;
109 /** @brief Internal storage for property
110 * @ref RgbColorSpace::profilePcsColorModel */
111 cmsColorSpaceSignature m_profilePcsColorModel;
112 /** @brief Internal storage for property
113 * @ref RgbColorSpace::profileTagSignatures */
114 QStringList m_profileTagSignatures;
115 /** @brief A handle to a LittleCMS transform. */
116 cmsHTRANSFORM m_transformCielabD50ToRgb16Handle = nullptr;
117 /** @brief A handle to a LittleCMS transform. */
118 cmsHTRANSFORM m_transformCielabD50ToRgbHandle = nullptr;
119 /** @brief A handle to a LittleCMS transform. */
120 cmsHTRANSFORM m_transformRgbToCielabD50Handle = nullptr;
121
122 // Functions:
123 static void deleteTransform(cmsHTRANSFORM *transformHandle);
124 [[nodiscard]] double detectMaximumCielchD50Chroma() const;
125 [[nodiscard]] double detectMaximumOklchChroma() const;
126 [[nodiscard]] bool initialize(cmsHPROFILE rgbProfileHandle);
127 [[nodiscard]] static QDateTime profileCreationDateTime(cmsHPROFILE profileHandle);
128 [[nodiscard]] static QVersionNumber profileIccVersion(cmsHPROFILE profileHandle);
129 [[nodiscard]] static QString profileInformation(cmsHPROFILE profileHandle, cmsInfoType infoType);
130 [[nodiscard]] static QStringList profileTagSignatures(cmsHPROFILE profileHandle);
131
132 /** @brief The rendering intents supported by the LittleCMS library.
133 *
134 * Contains all rendering intents supported by the LittleCMS library
135 * against which this we are currently linking. Each entry contains
136 * the code and the (english-language) description just as provided
137 * by LittleCMS.
138 *
139 * Note that LittleCMS supports as built-in intents the four official
140 * ICC intents and also some other, non-ICC intents. Furthermore,
141 * LittleCMS plugins can provide even more intents. As of LittleCMS 2.13
142 * the following built-in intents are available:
143 *
144 * | Type | Macro name | Code |
145 * | :------ | :-------------------------------------------- | ---: |
146 * | ICC | INTENT_PERCEPTUAL | 0 |
147 * | ICC | INTENT_RELATIVE_COLORIMETRIC | 1 |
148 * | ICC | INTENT_SATURATION | 2 |
149 * | ICC | INTENT_ABSOLUTE_COLORIMETRIC | 3 |
150 * | Non-ICC | INTENT_PRESERVE_K_ONLY_PERCEPTUAL | 10 |
151 * | Non-ICC | INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC | 11 |
152 * | Non-ICC | INTENT_PRESERVE_K_ONLY_SATURATION | 12 |
153 * | Non-ICC | INTENT_PRESERVE_K_PLANE_PERCEPTUAL | 13 |
154 * | Non-ICC | INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC | 14 |
155 * | Non-ICC | INTENT_PRESERVE_K_PLANE_SATURATION | 15 |
156 *
157 * @todo Either actually <em>use</em> this code or <em>remove</em> this
158 * code. */
159 static inline const QMap<cmsUInt32Number, QString> intentList = getIntentList();
160
161 /** @brief Precision of HSV hue during maximum-chroma detection.
162 *
163 * @todo A value smaller than 0.001 does not make sense
164 * currently, because QColor has only a limited precision for
165 * HSV conversions. Furthermore, since Qt6 it’s floating point interface
166 * has been defined with “float”. For a more exact solution, we would
167 * have to implement our own HSV conversion first. */
168 static constexpr double chromaDetectionHuePrecision = gamutPrecisionCielab;
169 /** @brief Increment factor for the maximum-chroma detection.
170 *
171 * The maximum-chroma detection, regardless of the precision,
172 * might always return a value that is a bit too small. However,
173 * we want to have @ref RgbColorSpace::profileMaximumCielchD50Chroma and
174 * @ref RgbColorSpace::profileMaximumOklchChroma values that are equal
175 * or slightly bigger than the actual maximum-chroma, to make sure to
176 * not exclude valid values. Therefore, @ref detectMaximumCielchD50Chroma()
177 * and @ref detectMaximumOklchChroma use this increment factor to
178 * slightly increment the outcome of the chroma detection relative to
179 * the original value, as a safety margin. Note that additionally,
180 * an absolute increment should also be added, because of limited
181 * precision in floating point operations. */
182 static constexpr double chromaDetectionIncrementFactor = 1.02;
183 /** @brief For detecting CIELab in-gamut or out-of-gamut colors.
184 *
185 * For gamut detection, a roundtrip conversion is performed: Lab values
186 * are converted to an RGB color space and backwards. If the distance
187 * in euclidean space between the the original Lab value and the result
188 * of the roundtrip is smaller than a certain value, it is considered
189 * as an in-gamut value.
190 *
191 * This deviation limit should be as small as possible for a more correct
192 * gamut boundary. But it must unfortunately also be big enough to ignore
193 * rounding errors. The current value was chosen by trial-and-error. */
194 static constexpr qreal cielabDeviationLimit = 0.5;
195 /** @brief For detecting Oklab in-gamut or out-of-gamut colors.
196 *
197 * For gamut detection, a roundtrip conversion is performed: Lab values
198 * are converted to an RGB color space and backwards. If the distance
199 * in euclidean space between the the original Lab value and the result
200 * of the roundtrip is smaller than a certain value, it is considered
201 * as an in-gamut value.
202 *
203 * This deviation limit should be as small as possible for a more correct
204 * gamut boundary. But it must unfortunately also be big enough to ignore
205 * rounding errors. The current value was chosen by trial-and-error. */
206 static constexpr qreal oklabDeviationLimit = 0.001;
207
208private:
209 Q_DISABLE_COPY(RgbColorSpacePrivate)
210
211 /** @brief Pointer to the object from which <em>this</em> object
212 * is the private implementation. */
213 ConstPropagatingRawPointer<RgbColorSpace> q_pointer;
214};
215
216} // namespace PerceptualColor
217
218#endif // RGBCOLORSPACE_P_H
The namespace of this library.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:18:38 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.