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

KDE's Doxygen guidelines are available online.