18#include <QtGui/qtguiglobal.h>
19#include <QtCore/qpoint.h>
20#include <QtCore/private/qglobal_p.h>
21#include <QtCore/private/qsimd_p.h>
30 QColorVector() =
default;
31 constexpr QColorVector(
float x,
float y,
float z,
float w = 0.0f)
noexcept : x(x), y(y), z(z), w(w) { }
32 static constexpr QColorVector fromXYChromaticity(QPointF chr)
33 {
return {
float(chr.x() / chr.y()), 1.0f,
float((1.0f - chr.x() - chr.y()) / chr.y())}; }
39 constexpr bool isNull()
const noexcept
41 return !x && !y && !z && !w;
43 bool isValid()
const noexcept
45 return std::isfinite(x) && std::isfinite(y) && std::isfinite(z);
48 static constexpr bool isValidChromaticity(
const QPointF &chr)
50 if (chr.x() < qreal(0.0) || chr.x() > qreal(1.0))
52 if (chr.y() <= qreal(0.0) || chr.y() > qreal(1.0))
54 if (chr.x() + chr.y() > qreal(1.0))
59 constexpr QColorVector operator*(
float f)
const {
return QColorVector(x * f, y * f, z * f, w * f); }
60 constexpr QColorVector operator+(
const QColorVector &v)
const {
return QColorVector(x + v.x, y + v.y, z + v.z, w + v.w); }
61 constexpr QColorVector operator-(
const QColorVector &v)
const {
return QColorVector(x - v.x, y - v.y, z - v.z, w - v.w); }
62 void operator+=(
const QColorVector &v) { x += v.x; y += v.y; z += v.z; w += v.w; }
64 QPointF toChromaticity()
const
68 float mag = 1.0f / (x + y + z);
69 return QPointF(x * mag, y * mag);
73 static constexpr QPointF D50Chromaticity() {
return QPointF(0.34567, 0.35850); }
74 static constexpr QPointF D65Chromaticity() {
return QPointF(0.31271, 0.32902); }
75 static constexpr QColorVector D50() {
return fromXYChromaticity(D50Chromaticity()); }
76 static constexpr QColorVector D65() {
return fromXYChromaticity(D65Chromaticity()); }
78 QColorVector xyzToLab()
const
80 constexpr QColorVector ref = D50();
81 constexpr float eps = 0.008856f;
82 constexpr float kap = 903.3f;
84 const __m128 iref = _mm_setr_ps(1.f / ref.x, 1.f / ref.y, 1.f / ref.z, 0.f);
85 __m128 v = _mm_loadu_ps(&x);
86 v = _mm_mul_ps(v, iref);
88 const __m128 f3 = _mm_set1_ps(3.f);
89 __m128 est = _mm_add_ps(_mm_set1_ps(0.25f), _mm_mul_ps(v, _mm_set1_ps(0.75f)));
90 __m128 estsq = _mm_mul_ps(est, est);
91 est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
92 _mm_rcp_ps(_mm_mul_ps(estsq, f3))));
93 estsq = _mm_mul_ps(est, est);
94 est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
95 _mm_rcp_ps(_mm_mul_ps(estsq, f3))));
96 estsq = _mm_mul_ps(est, est);
97 est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
98 _mm_rcp_ps(_mm_mul_ps(estsq, f3))));
99 estsq = _mm_mul_ps(est, est);
100 est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
101 _mm_rcp_ps(_mm_mul_ps(estsq, f3))));
103 __m128 kapmul = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(v, _mm_set1_ps(kap)), _mm_set1_ps(16.f)),
104 _mm_set1_ps(1.f / 116.f));
105 __m128 cmpgt = _mm_cmpgt_ps(v, _mm_set1_ps(eps));
106#if defined(__SSE4_1__)
107 v = _mm_blendv_ps(kapmul, est, cmpgt);
109 v = _mm_or_ps(_mm_and_ps(cmpgt, est), _mm_andnot_ps(cmpgt, kapmul));
111 alignas(16)
float out[4];
112 _mm_store_ps(out, v);
113 const float L = 116.f * out[1] - 16.f;
114 const float a = 500.f * (out[0] - out[1]);
115 const float b = 200.f * (out[1] - out[2]);
117 float xr = x * (1.f / ref.x);
118 float yr = y * (1.f / ref.y);
119 float zr = z * (1.f / ref.z);
125 fx = (kap * xr + 16.f) * (1.f / 116.f);
129 fy = (kap * yr + 16.f) * (1.f / 116.f);
133 fz = (kap * zr + 16.f) * (1.f / 116.f);
135 const float L = 116.f * fy - 16.f;
136 const float a = 500.f * (fx - fy);
137 const float b = 200.f * (fy - fz);
140 return QColorVector(L * (1.f / 100.f), (a + 128.f) * (1.f / 255.f), (b + 128.f) * (1.f / 255.f));
143 QColorVector labToXyz()
const
145 constexpr QColorVector ref = D50();
146 constexpr float eps = 0.008856f;
147 constexpr float kap = 903.3f;
150 const float L = x * 100.f;
151 const float a = (y * 255.f) - 128.f;
152 const float b = (z * 255.f) - 128.f;
154 float fy = (L + 16.f) * (1.f / 116.f);
155 float fx = fy + (a * (1.f / 500.f));
156 float fz = fy - (b * (1.f / 200.f));
159 if (fx * fx * fx > eps)
162 xr = (116.f * fx - 16) * (1.f / kap);
166 yr = L * (1.f / kap);
167 if (fz * fz * fz > eps)
170 zr = (116.f * fz - 16) * (1.f / kap);
175 return QColorVector(xr, yr, zr);
177 friend inline bool comparesEqual(
const QColorVector &lhs,
const QColorVector &rhs)
noexcept;
178 Q_DECLARE_EQUALITY_COMPARABLE(QColorVector)
181 static float fastCbrt(
float x)
184 float est = 0.25f + (x * 0.75f);
185 est -= ((est * est * est) - x) / (3.f * (est * est));
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));
194inline bool comparesEqual(
const QColorVector &v1,
const QColorVector &v2)
noexcept
196 return (
std::abs(v1.x - v2.x) < (1.0f / 2048.0f))
197 && (
std::abs(v1.y - v2.y) < (1.0f / 2048.0f))
198 && (
std::abs(v1.z - v2.z) < (1.0f / 2048.0f))
199 && (
std::abs(v1.w - v2.w) < (1.0f / 2048.0f));
214 return r.isNull() && g.isNull() && b.isNull();
218 return r.x * (b.z * g.y - g.z * b.y) -
219 r.y * (b.z * g.x - g.z * b.x) +
220 r.z * (b.y * g.x - g.y * b.x);
225 return std::isnormal(determinant());
234 float det = determinant();
237 inv.r.x = (g.y * b.z - b.y * g.z) * det;
238 inv.r.y = (b.y * r.z - r.y * b.z) * det;
239 inv.r.z = (r.y * g.z - g.y * r.z) * det;
240 inv.g.x = (b.x * g.z - g.x * b.z) * det;
241 inv.g.y = (r.x * b.z - b.x * r.z) * det;
242 inv.g.z = (g.x * r.z - r.x * g.z) * det;
243 inv.b.x = (g.x * b.y - b.x * g.y) * det;
244 inv.b.y = (b.x * r.y - r.x * b.y) * det;
245 inv.b.z = (r.x * g.y - g.x * r.y) * det;
251 comb.r.x = a.r.x * o.r.x + a.g.x * o.r.y + a.b.x * o.r.z;
252 comb.g.x = a.r.x * o.g.x + a.g.x * o.g.y + a.b.x * o.g.z;
253 comb.b.x = a.r.x * o.b.x + a.g.x * o.b.y + a.b.x * o.b.z;
255 comb.r.y = a.r.y * o.r.x + a.g.y * o.r.y + a.b.y * o.r.z;
256 comb.g.y = a.r.y * o.g.x + a.g.y * o.g.y + a.b.y * o.g.z;
257 comb.b.y = a.r.y * o.b.x + a.g.y * o.b.y + a.b.y * o.b.z;
259 comb.r.z = a.r.z * o.r.x + a.g.z * o.r.y + a.b.z * o.r.z;
260 comb.g.z = a.r.z * o.g.x + a.g.z * o.g.y + a.b.z * o.g.z;
261 comb.b.z = a.r.z * o.b.x + a.g.z * o.b.y + a.b.z * o.b.z;
265 QColorVector
map(
const QColorVector &c)
const
267 return QColorVector { c.x * r.x + c.y * g.x + c.z * b.x,
268 c.x * r.y + c.y * g.y + c.z * b.y,
269 c.x * r.z + c.y * g.z + c.z * b.z };
273 return QColorMatrix { { r.x, g.x, b.x },
280 return { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } };
284 return QColorMatrix { { v.x, 0.0f, 0.0f },
286 { 0.0f, 0.0f, v.z } };
290 constexpr QColorVector whitePointD50 = QColorVector::D50();
291 if (whitePoint != whitePointD50) {
295 const QColorMatrix abrad = { { 0.8951f, -0.7502f, 0.0389f },
296 { 0.2664f, 1.7135f, -0.0685f },
297 { -0.1614f, 0.0367f, 1.0296f } };
298 const QColorMatrix abradinv = { { 0.9869929f, 0.4323053f, -0.0085287f },
299 { -0.1470543f, 0.5183603f, 0.0400428f },
300 { 0.1599627f, 0.0492912f, 0.9684867f } };
302 const QColorVector srcCone = abrad
.map(whitePoint
);
303 if (srcCone.x && srcCone.y && srcCone.z) {
304 const QColorVector dstCone = abrad
.map(whitePointD50
);
305 const QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
306 { 0, dstCone.y / srcCone.y, 0 },
307 { 0, 0, dstCone.z / srcCone.z } };
308 return abradinv
* (wToD50
* abrad);
317 return QColorMatrix { { 0.4360217452f, 0.2224751115f, 0.0139281144f },
318 { 0.3851087987f, 0.7169067264f, 0.0971015394f },
319 { 0.1430812478f, 0.0606181994f, 0.7141585946f } };
323 return QColorMatrix { { 0.6097189188f, 0.3111021519f, 0.0194766335f },
324 { 0.2052682191f, 0.6256770492f, 0.0608891509f },
325 { 0.1492247432f, 0.0632209629f, 0.7448224425f } };
329 return QColorMatrix { { 0.5150973201f, 0.2411795557f, -0.0010491034f },
330 { 0.2919696569f, 0.6922441125f, 0.0418830328f },
331 { 0.1571449190f, 0.0665764511f, 0.7843542695f } };
335 return QColorMatrix { { 0.7976672649f, 0.2880374491f, 0.0000000000f },
336 { 0.1351922452f, 0.7118769884f, 0.0000000000f },
337 { 0.0313525312f, 0.0000856627f, 0.8251883388f } };
341 return QColorMatrix { { 0.673447f, 0.279037f, -0.00192261f },
342 { 0.165665f, 0.675339f, 0.0299835f },
343 { 0.125092f, 0.0456238f, 0.797134f } };
351 return (m1.r == m2.r) && (m1.g == m2.g) && (m1.b == m2.b);
QColorVector apply(const QColorVector &v) const
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]