19#include <QtGui/qtguiglobal.h>
20#include <QtCore/qpoint.h>
21#include <QtCore/private/qglobal_p.h>
22#include <QtCore/private/qsimd_p.h>
31 QColorVector() =
default;
32 constexpr QColorVector(
float x,
float y,
float z,
float w = 0.0f)
noexcept : x(x), y(y), z(z), w(w) { }
33 static constexpr QColorVector fromXYChromaticity(QPointF chr)
34 {
return {
float(chr.x() / chr.y()), 1.0f,
float((1.0f - chr.x() - chr.y()) / chr.y())}; }
40 constexpr bool isNull()
const noexcept
42 return !x && !y && !z && !w;
44 bool isValid()
const noexcept
46 return std::isfinite(x) && std::isfinite(y) && std::isfinite(z);
49 static constexpr bool isValidChromaticity(
const QPointF &chr)
51 if (chr.x() < qreal(0.0) || chr.x() > qreal(1.0))
53 if (chr.y() <= qreal(0.0) || chr.y() > qreal(1.0))
55 if (chr.x() + chr.y() > qreal(1.0))
60 constexpr QColorVector operator*(
float f)
const {
return QColorVector(x * f, y * f, z * f, w * f); }
61 constexpr QColorVector operator+(
const QColorVector &v)
const {
return QColorVector(x + v.x, y + v.y, z + v.z, w + v.w); }
62 constexpr QColorVector operator-(
const QColorVector &v)
const {
return QColorVector(x - v.x, y - v.y, z - v.z, w - v.w); }
63 void operator+=(
const QColorVector &v) { x += v.x; y += v.y; z += v.z; w += v.w; }
65 QPointF toChromaticity()
const
69 float mag = 1.0f / (x + y + z);
70 return QPointF(x * mag, y * mag);
74 static constexpr QPointF D50Chromaticity() {
return QPointF(0.34567, 0.35850); }
75 static constexpr QPointF D65Chromaticity() {
return QPointF(0.31271, 0.32902); }
76 static constexpr QColorVector D50() {
return fromXYChromaticity(D50Chromaticity()); }
77 static constexpr QColorVector D65() {
return fromXYChromaticity(D65Chromaticity()); }
79 QColorVector xyzToLab()
const
81 constexpr QColorVector ref = D50();
82 constexpr float eps = 0.008856f;
83 constexpr float kap = 903.3f;
85 const __m128 iref = _mm_setr_ps(1.f / ref.x, 1.f / ref.y, 1.f / ref.z, 0.f);
86 __m128 v = _mm_loadu_ps(&x);
87 v = _mm_mul_ps(v, iref);
89 const __m128 f3 = _mm_set1_ps(3.f);
90 __m128 est = _mm_add_ps(_mm_set1_ps(0.25f), _mm_mul_ps(v, _mm_set1_ps(0.75f)));
91 __m128 estsq = _mm_mul_ps(est, est);
92 est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
93 _mm_rcp_ps(_mm_mul_ps(estsq, f3))));
94 estsq = _mm_mul_ps(est, est);
95 est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
96 _mm_rcp_ps(_mm_mul_ps(estsq, f3))));
97 estsq = _mm_mul_ps(est, est);
98 est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
99 _mm_rcp_ps(_mm_mul_ps(estsq, f3))));
100 estsq = _mm_mul_ps(est, est);
101 est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
102 _mm_rcp_ps(_mm_mul_ps(estsq, f3))));
104 __m128 kapmul = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(v, _mm_set1_ps(kap)), _mm_set1_ps(16.f)),
105 _mm_set1_ps(1.f / 116.f));
106 __m128 cmpgt = _mm_cmpgt_ps(v, _mm_set1_ps(eps));
107#if defined(__SSE4_1__)
108 v = _mm_blendv_ps(kapmul, est, cmpgt);
110 v = _mm_or_ps(_mm_and_ps(cmpgt, est), _mm_andnot_ps(cmpgt, kapmul));
112 alignas(16)
float out[4];
113 _mm_store_ps(out, v);
114 const float L = 116.f * out[1] - 16.f;
115 const float a = 500.f * (out[0] - out[1]);
116 const float b = 200.f * (out[1] - out[2]);
118 float xr = x * (1.f / ref.x);
119 float yr = y * (1.f / ref.y);
120 float zr = z * (1.f / ref.z);
126 fx = (kap * xr + 16.f) * (1.f / 116.f);
130 fy = (kap * yr + 16.f) * (1.f / 116.f);
134 fz = (kap * zr + 16.f) * (1.f / 116.f);
136 const float L = 116.f * fy - 16.f;
137 const float a = 500.f * (fx - fy);
138 const float b = 200.f * (fy - fz);
141 return QColorVector(L * (1.f / 100.f), (a + 128.f) * (1.f / 255.f), (b + 128.f) * (1.f / 255.f));
144 QColorVector labToXyz()
const
146 constexpr QColorVector ref = D50();
147 constexpr float eps = 0.008856f;
148 constexpr float kap = 903.3f;
151 const float L = x * 100.f;
152 const float a = (y * 255.f) - 128.f;
153 const float b = (z * 255.f) - 128.f;
155 float fy = (L + 16.f) * (1.f / 116.f);
156 float fx = fy + (a * (1.f / 500.f));
157 float fz = fy - (b * (1.f / 200.f));
160 if (fx * fx * fx > eps)
163 xr = (116.f * fx - 16) * (1.f / kap);
167 yr = L * (1.f / kap);
168 if (fz * fz * fz > eps)
171 zr = (116.f * fz - 16) * (1.f / kap);
176 return QColorVector(xr, yr, zr);
178 friend inline bool comparesEqual(
const QColorVector &lhs,
const QColorVector &rhs)
noexcept;
179 Q_DECLARE_EQUALITY_COMPARABLE(QColorVector)
182 static float fastCbrt(
float x)
185 float est = 0.25f + (x * 0.75f);
186 est -= ((est * est * est) - x) / (3.f * (est * est));
187 est -= ((est * est * est) - x) / (3.f * (est * est));
188 est -= ((est * est * est) - x) / (3.f * (est * est));
189 est -= ((est * est * est) - x) / (3.f * (est * est));
195inline bool comparesEqual(
const QColorVector &v1,
const QColorVector &v2)
noexcept
197 return (
std::abs(v1.x - v2.x) < (1.0f / 2048.0f))
198 && (
std::abs(v1.y - v2.y) < (1.0f / 2048.0f))
199 && (
std::abs(v1.z - v2.z) < (1.0f / 2048.0f))
200 && (
std::abs(v1.w - v2.w) < (1.0f / 2048.0f));
215 return r.isNull() && g.isNull() && b.isNull();
219 return r.x * (b.z * g.y - g.z * b.y) -
220 r.y * (b.z * g.x - g.z * b.x) +
221 r.z * (b.y * g.x - g.y * b.x);
226 return std::isnormal(determinant());
235 float det = determinant();
238 inv.r.x = (g.y * b.z - b.y * g.z) * det;
239 inv.r.y = (b.y * r.z - r.y * b.z) * det;
240 inv.r.z = (r.y * g.z - g.y * r.z) * det;
241 inv.g.x = (b.x * g.z - g.x * b.z) * det;
242 inv.g.y = (r.x * b.z - b.x * r.z) * det;
243 inv.g.z = (g.x * r.z - r.x * g.z) * det;
244 inv.b.x = (g.x * b.y - b.x * g.y) * det;
245 inv.b.y = (b.x * r.y - r.x * b.y) * det;
246 inv.b.z = (r.x * g.y - g.x * r.y) * det;
252 comb.r.x = a.r.x * o.r.x + a.g.x * o.r.y + a.b.x * o.r.z;
253 comb.g.x = a.r.x * o.g.x + a.g.x * o.g.y + a.b.x * o.g.z;
254 comb.b.x = a.r.x * o.b.x + a.g.x * o.b.y + a.b.x * o.b.z;
256 comb.r.y = a.r.y * o.r.x + a.g.y * o.r.y + a.b.y * o.r.z;
257 comb.g.y = a.r.y * o.g.x + a.g.y * o.g.y + a.b.y * o.g.z;
258 comb.b.y = a.r.y * o.b.x + a.g.y * o.b.y + a.b.y * o.b.z;
260 comb.r.z = a.r.z * o.r.x + a.g.z * o.r.y + a.b.z * o.r.z;
261 comb.g.z = a.r.z * o.g.x + a.g.z * o.g.y + a.b.z * o.g.z;
262 comb.b.z = a.r.z * o.b.x + a.g.z * o.b.y + a.b.z * o.b.z;
266 QColorVector
map(
const QColorVector &c)
const
268 return QColorVector { c.x * r.x + c.y * g.x + c.z * b.x,
269 c.x * r.y + c.y * g.y + c.z * b.y,
270 c.x * r.z + c.y * g.z + c.z * b.z };
274 return QColorMatrix { { r.x, g.x, b.x },
281 return { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } };
285 return QColorMatrix { { v.x, 0.0f, 0.0f },
287 { 0.0f, 0.0f, v.z } };
291 constexpr QColorVector whitePointD50 = QColorVector::D50();
292 if (whitePoint != whitePointD50) {
296 const QColorMatrix abrad = { { 0.8951f, -0.7502f, 0.0389f },
297 { 0.2664f, 1.7135f, -0.0685f },
298 { -0.1614f, 0.0367f, 1.0296f } };
299 const QColorMatrix abradinv = { { 0.9869929f, 0.4323053f, -0.0085287f },
300 { -0.1470543f, 0.5183603f, 0.0400428f },
301 { 0.1599627f, 0.0492912f, 0.9684867f } };
303 const QColorVector srcCone = abrad
.map(whitePoint
);
304 if (srcCone.x && srcCone.y && srcCone.z) {
305 const QColorVector dstCone = abrad
.map(whitePointD50
);
306 const QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
307 { 0, dstCone.y / srcCone.y, 0 },
308 { 0, 0, dstCone.z / srcCone.z } };
309 return abradinv
* (wToD50
* abrad);
318 return QColorMatrix { { 0.4360217452f, 0.2224751115f, 0.0139281144f },
319 { 0.3851087987f, 0.7169067264f, 0.0971015394f },
320 { 0.1430812478f, 0.0606181994f, 0.7141585946f } };
324 return QColorMatrix { { 0.6097189188f, 0.3111021519f, 0.0194766335f },
325 { 0.2052682191f, 0.6256770492f, 0.0608891509f },
326 { 0.1492247432f, 0.0632209629f, 0.7448224425f } };
330 return QColorMatrix { { 0.5150973201f, 0.2411795557f, -0.0010491034f },
331 { 0.2919696569f, 0.6922441125f, 0.0418830328f },
332 { 0.1571449190f, 0.0665764511f, 0.7843542695f } };
336 return QColorMatrix { { 0.7976672649f, 0.2880374491f, 0.0000000000f },
337 { 0.1351922452f, 0.7118769884f, 0.0000000000f },
338 { 0.0313525312f, 0.0000856627f, 0.8251883388f } };
342 return QColorMatrix { { 0.673447f, 0.279037f, -0.00192261f },
343 { 0.165665f, 0.675339f, 0.0299835f },
344 { 0.125092f, 0.0456238f, 0.797134f } };
352 return (m1.r == m2.r) && (m1.g == m2.g) && (m1.b == m2.b);
QList< QColorVector > table
QColorMatrix inverted() const
static QColorMatrix toXyzFromSRgb()
static QColorMatrix toXyzFromAdobeRgb()
friend bool comparesEqual(const QColorMatrix &lhs, const QColorMatrix &rhs) noexcept
constexpr float determinant() const
static QColorMatrix identity()
QColorMatrix transposed() const
static QColorMatrix fromScale(QColorVector v)
friend constexpr QColorMatrix operator*(const QColorMatrix &a, const QColorMatrix &o)
bool isIdentity() const noexcept
static QColorMatrix toXyzFromDciP3D65()
static QColorMatrix chromaticAdaptation(const QColorVector &whitePoint)
static QColorMatrix toXyzFromProPhotoRgb()
QColorVector map(const QColorVector &c) const
static QColorMatrix toXyzFromBt2020()
constexpr bool isNull() const
void setTransferFunctionTables(const QList< uint16_t > &redTransferFunctionTable, const QList< uint16_t > &greenTransferFunctionTable, const QList< uint16_t > &blueTransferFunctionTable)
QColorSpacePrivate(QPointF whitePoint, const QList< uint16_t > &transferFunctionTable)
QColorSpacePrivate(QPointF whitePoint, QColorSpace::TransferFunction transferFunction, float gamma)
QColorSpacePrivate(const QColorSpace::PrimaryPoints &primaries, const QList< uint16_t > &transferFunctionTable)
QColorTransform transformationToColorSpace(const QColorSpacePrivate *out) const
void clearElementListProcessingForEdit()
void setTransferFunctionTable(const QList< uint16_t > &transferFunctionTable)
QColorTransform transformationToXYZ() const
bool isThreeComponentMatrix() const
QColorSpacePrivate(const QColorSpace::PrimaryPoints &primaries, const QList< uint16_t > &redTransferFunctionTable, const QList< uint16_t > &greenTransferFunctionTable, const QList< uint16_t > &blueRransferFunctionTable)
QColorSpacePrivate(const QColorSpacePrivate &other)=default
static const QColorSpacePrivate * get(const QColorSpace &colorSpace)
QColorSpacePrivate(const QColorSpace::PrimaryPoints &primaries, QColorSpace::TransferFunction transferFunction, float gamma)
void setTransferFunction()
static QColorSpacePrivate * get(QColorSpace &colorSpace)
void identifyColorSpace()
bool isValid() const noexcept
QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace)
bool equals(const QColorSpacePrivate *other) const
Combined button and popup list for selecting options.
bool comparesEqual(const QColorVector &v1, const QColorVector &v2) noexcept
static void cleanupPredefinedColorspaces()
static bool compareElement(const QColorSpacePrivate::TransferElement &element, const QColorSpacePrivate::TransferElement &other)
QDebug operator<<(QDebug dbg, const QColorCLUT &)
QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
QDebug operator<<(QDebug dbg, const QColorMatrix &)
static bool compareElement(const QColorMatrix &element, const QColorMatrix &other)
QDataStream & operator>>(QDataStream &s, QColorSpace &colorSpace)
QDataStream & operator<<(QDataStream &s, const QColorSpace &image)
QDebug operator<<(QDebug dbg, const QColorVector &)
QColorMatrix qColorSpacePrimaryPointsToXyzMatrix(const QColorSpace::PrimaryPoints &primaries)
static bool compareElements(const T &element, const QColorSpacePrivate::Element &other)
static bool compareElement(const QColorCLUT &element, const QColorCLUT &other)
static bool compareElement(const QColorVector &element, const QColorVector &other)
QDebug operator<<(QDebug dbg, const QColorSpacePrivate::TransferElement &)
QT_BEGIN_NAMESPACE bool qColorSpacePrimaryPointsAreValid(const QColorSpace::PrimaryPoints &primaries)
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
const std::shared_ptr< QColorTrcLut > & operator[](int i) const
std::shared_ptr< QColorTrcLut > & operator[](int i)
std::shared_ptr< QColorTrcLut > table[3]