summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qcolorspace.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting/qcolorspace.cpp')
-rw-r--r--src/gui/painting/qcolorspace.cpp159
1 files changed, 135 insertions, 24 deletions
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 24785f7b61..8d3bbbe412 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -53,6 +53,104 @@
QT_BEGIN_NAMESPACE
+QBasicMutex QColorSpacePrivate::s_lutWriteLock;
+
+QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Gamut gamut)
+{
+ switch (gamut) {
+ case QColorSpace::Gamut::SRgb:
+ redPoint = QPointF(0.640, 0.330);
+ greenPoint = QPointF(0.300, 0.600);
+ bluePoint = QPointF(0.150, 0.060);
+ whitePoint = QColorVector::D65Chromaticity();
+ break;
+ case QColorSpace::Gamut::DciP3D65:
+ redPoint = QPointF(0.680, 0.320);
+ greenPoint = QPointF(0.265, 0.690);
+ bluePoint = QPointF(0.150, 0.060);
+ whitePoint = QColorVector::D65Chromaticity();
+ break;
+ case QColorSpace::Gamut::Bt2020:
+ redPoint = QPointF(0.708, 0.292);
+ greenPoint = QPointF(0.190, 0.797);
+ bluePoint = QPointF(0.131, 0.046);
+ whitePoint = QColorVector::D65Chromaticity();
+ break;
+ case QColorSpace::Gamut::AdobeRgb:
+ redPoint = QPointF(0.640, 0.330);
+ greenPoint = QPointF(0.210, 0.710);
+ bluePoint = QPointF(0.150, 0.060);
+ whitePoint = QColorVector::D65Chromaticity();
+ break;
+ case QColorSpace::Gamut::ProPhotoRgb:
+ redPoint = QPointF(0.7347, 0.2653);
+ greenPoint = QPointF(0.1596, 0.8404);
+ bluePoint = QPointF(0.0366, 0.0001);
+ whitePoint = QColorVector::D50Chromaticity();
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+bool QColorSpacePrimaries::areValid() const
+{
+ if (!QColorVector::isValidChromaticity(redPoint))
+ return false;
+ if (!QColorVector::isValidChromaticity(greenPoint))
+ return false;
+ if (!QColorVector::isValidChromaticity(bluePoint))
+ return false;
+ if (!QColorVector::isValidChromaticity(whitePoint))
+ return false;
+ return true;
+}
+
+QColorMatrix QColorSpacePrimaries::toXyzMatrix() const
+{
+ // This converts to XYZ in some undefined scale.
+ QColorMatrix toXyz = { QColorVector(redPoint),
+ QColorVector(greenPoint),
+ QColorVector(bluePoint) };
+
+ // Since the white point should be (1.0, 1.0, 1.0) in the
+ // input, we can figure out the scale by using the
+ // inverse conversion on the white point.
+ QColorVector wXyz(whitePoint);
+ QColorVector whiteScale = toXyz.inverted().map(wXyz);
+
+ // Now we have scaled conversion to XYZ relative to the given whitepoint
+ toXyz = toXyz * QColorMatrix::fromScale(whiteScale);
+
+ // But we want a conversion to XYZ relative to D50
+ QColorVector wXyzD50 = QColorVector::D50();
+
+ if (wXyz != wXyzD50) {
+ // Do chromatic adaptation to map our white point to XYZ D50.
+
+ // The Bradford method chromatic adaptation matrix:
+ QColorMatrix abrad = { { 0.8951f, -0.7502f, 0.0389f },
+ { 0.2664f, 1.7135f, -0.0685f },
+ { -0.1614f, 0.0367f, 1.0296f } };
+ QColorMatrix abradinv = { { 0.9869929f, 0.4323053f, -0.0085287f },
+ { -0.1470543f, 0.5183603f, 0.0400428f },
+ { 0.1599627f, 0.0492912f, 0.9684867f } };
+
+ QColorVector srcCone = abrad.map(wXyz);
+ QColorVector dstCone = abrad.map(wXyzD50);
+
+ QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
+ { 0, dstCone.y / srcCone.y, 0 },
+ { 0, 0, dstCone.z / srcCone.z } };
+
+
+ QColorMatrix chromaticAdaptation = abradinv * (wToD50 * abrad);
+ toXyz = chromaticAdaptation * toXyz;
+ }
+
+ return toXyz;
+}
+
QColorSpacePrivate::QColorSpacePrivate()
: id(QColorSpace::Unknown)
, gamut(QColorSpace::Gamut::Custom)
@@ -128,6 +226,21 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Gamut gamut, QColorSpace::Tr
initialize();
}
+QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
+ QColorSpace::TransferFunction fun,
+ float gamma)
+ : gamut(QColorSpace::Gamut::Custom)
+ , transferFunction(fun)
+ , gamma(gamma)
+{
+ Q_ASSERT(primaries.areValid());
+ toXyz = primaries.toXyzMatrix();
+ whitePoint = QColorVector(primaries.whitePoint);
+ if (!identifyColorSpace())
+ id = QColorSpace::Unknown;
+ setTransferFunction();
+}
+
bool QColorSpacePrivate::identifyColorSpace()
{
switch (gamut) {
@@ -195,33 +308,14 @@ void QColorSpacePrivate::initialize()
void QColorSpacePrivate::setToXyzMatrix()
{
- switch (gamut) {
- case QColorSpace::Gamut::SRgb:
- toXyz = QColorMatrix::toXyzFromSRgb();
- whitePoint = QColorVector::D65();
- return;
- case QColorSpace::Gamut::AdobeRgb:
- toXyz = QColorMatrix::toXyzFromAdobeRgb();
- whitePoint = QColorVector::D65();
- return;
- case QColorSpace::Gamut::DciP3D65:
- toXyz = QColorMatrix::toXyzFromDciP3D65();
- whitePoint = QColorVector::D65();
- return;
- case QColorSpace::Gamut::ProPhotoRgb:
- toXyz = QColorMatrix::toXyzFromProPhotoRgb();
- whitePoint = QColorVector::D50();
- return;
- case QColorSpace::Gamut::Bt2020:
- toXyz = QColorMatrix::toXyzFromBt2020();
- whitePoint = QColorVector::D65();
- return;
- case QColorSpace::Gamut::Custom:
+ if (gamut == QColorSpace::Gamut::Custom) {
toXyz = QColorMatrix::null();
whitePoint = QColorVector::D50();
return;
}
- Q_UNREACHABLE();
+ QColorSpacePrimaries primaries(gamut);
+ toXyz = primaries.toXyzMatrix();
+ whitePoint = QColorVector(primaries.whitePoint);
}
void QColorSpacePrivate::setTransferFunction()
@@ -386,6 +480,23 @@ QColorSpace::QColorSpace(QColorSpace::Gamut gamut, float gamma)
{
}
+/*!
+ Creates a custom colorspace with a gamut based on the chromaticities of the primary colors \a whitePoint,
+ \a redPoint, \a greenPoint and \a bluePoint, and using the transfer function \a fun and optionally \a gamma.
+ */
+QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
+ const QPointF &greenPoint, const QPointF &bluePoint,
+ QColorSpace::TransferFunction fun, float gamma)
+{
+ QColorSpacePrimaries primaries(whitePoint, redPoint, greenPoint, bluePoint);
+ if (!primaries.areValid()) {
+ qWarning() << "QColorSpace attempted constructed from invalid primaries:" << whitePoint << redPoint << greenPoint << bluePoint;
+ d_ptr = QColorSpace(QColorSpace::Undefined).d_ptr;
+ return;
+ }
+ d_ptr = new QColorSpacePrivate(primaries, fun, gamma);
+}
+
QColorSpace::~QColorSpace()
{
}
@@ -549,7 +660,7 @@ bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
\fn bool operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
\relates QColorSpace
- Returns \c true if colorspace \a colorspace1 is not equal to colorspace \a colorspace2;
+ Returns \c true if colorspace \a colorSpace1 is not equal to colorspace \a colorSpace2;
otherwise returns \c false
*/