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.cpp134
1 files changed, 101 insertions, 33 deletions
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 058a6cb566..3d763d577c 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -21,7 +21,7 @@ QT_BEGIN_NAMESPACE
Q_CONSTINIT QBasicMutex QColorSpacePrivate::s_lutWriteLock;
-Q_CONSTINIT static QAtomicPointer<QColorSpacePrivate> s_predefinedColorspacePrivates[QColorSpace::ProPhotoRgb] = {};
+Q_CONSTINIT static QAtomicPointer<QColorSpacePrivate> s_predefinedColorspacePrivates[QColorSpace::Bt2100Hlg] = {};
static void cleanupPredefinedColorspaces()
{
for (QAtomicPointer<QColorSpacePrivate> &ptr : s_predefinedColorspacePrivates) {
@@ -60,6 +60,12 @@ QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Primaries primaries)
bluePoint = QPointF(0.0366, 0.0001);
whitePoint = QColorVector::D50Chromaticity();
break;
+ case QColorSpace::Primaries::Bt2020:
+ redPoint = QPointF(0.708, 0.292);
+ greenPoint = QPointF(0.170, 0.797);
+ bluePoint = QPointF(0.131, 0.046);
+ whitePoint = QColorVector::D65Chromaticity();
+ break;
default:
Q_UNREACHABLE();
}
@@ -81,14 +87,14 @@ bool QColorSpacePrimaries::areValid() const
QColorMatrix QColorSpacePrimaries::toXyzMatrix() const
{
// This converts to XYZ in some undefined scale.
- QColorMatrix toXyz = { QColorVector(redPoint),
- QColorVector(greenPoint),
- QColorVector(bluePoint) };
+ QColorMatrix toXyz = { QColorVector::fromXYChromaticity(redPoint),
+ QColorVector::fromXYChromaticity(greenPoint),
+ QColorVector::fromXYChromaticity(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);
+ const auto wXyz = QColorVector::fromXYChromaticity(whitePoint);
QColorVector whiteScale = toXyz.inverted().map(wXyz);
// Now we have scaled conversion to XYZ relative to the given whitepoint
@@ -132,6 +138,21 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSp
transferFunction = QColorSpace::TransferFunction::ProPhotoRgb;
description = QStringLiteral("ProPhoto RGB");
break;
+ case QColorSpace::Bt2020:
+ primaries = QColorSpace::Primaries::Bt2020;
+ transferFunction = QColorSpace::TransferFunction::Bt2020;
+ description = QStringLiteral("BT.2020");
+ break;
+ case QColorSpace::Bt2100Pq:
+ primaries = QColorSpace::Primaries::Bt2020;
+ transferFunction = QColorSpace::TransferFunction::St2084;
+ description = QStringLiteral("BT.2100(PQ)");
+ break;
+ case QColorSpace::Bt2100Hlg:
+ primaries = QColorSpace::Primaries::Bt2020;
+ transferFunction = QColorSpace::TransferFunction::Hlg;
+ description = QStringLiteral("BT.2100(HLG)");
+ break;
default:
Q_UNREACHABLE();
}
@@ -155,7 +176,7 @@ QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
, transferFunction(transferFunction)
, colorModel(QColorSpace::ColorModel::Rgb)
, gamma(gamma)
- , whitePoint(primaries.whitePoint)
+ , whitePoint(QColorVector::fromXYChromaticity(primaries.whitePoint))
{
Q_ASSERT(primaries.areValid());
toXyz = primaries.toXyzMatrix();
@@ -173,7 +194,7 @@ QColorSpacePrivate::QColorSpacePrivate(const QPointF &whitePoint,
, transferFunction(transferFunction)
, colorModel(QColorSpace::ColorModel::Gray)
, gamma(gamma)
- , whitePoint(whitePoint)
+ , whitePoint(QColorVector::fromXYChromaticity(whitePoint))
{
chad = QColorMatrix::chromaticAdaptation(this->whitePoint);
toXyz = chad;
@@ -185,7 +206,7 @@ QColorSpacePrivate::QColorSpacePrivate(const QPointF &whitePoint, const QList<ui
, transferFunction(QColorSpace::TransferFunction::Custom)
, colorModel(QColorSpace::ColorModel::Gray)
, gamma(0)
- , whitePoint(whitePoint)
+ , whitePoint(QColorVector::fromXYChromaticity(whitePoint))
{
chad = QColorMatrix::chromaticAdaptation(this->whitePoint);
toXyz = chad;
@@ -209,7 +230,7 @@ QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries, co
, transferFunction(QColorSpace::TransferFunction::Custom)
, colorModel(QColorSpace::ColorModel::Rgb)
, gamma(0)
- , whitePoint(primaries.whitePoint)
+ , whitePoint(QColorVector::fromXYChromaticity(primaries.whitePoint))
{
Q_ASSERT(primaries.areValid());
toXyz = primaries.toXyzMatrix();
@@ -231,7 +252,7 @@ QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
{
Q_ASSERT(primaries.areValid());
toXyz = primaries.toXyzMatrix();
- whitePoint = QColorVector(primaries.whitePoint);
+ whitePoint = QColorVector::fromXYChromaticity(primaries.whitePoint);
chad = QColorMatrix::chromaticAdaptation(whitePoint);
toXyz = chad * toXyz;
setTransferFunctionTables(redTransferFunctionTable,
@@ -292,6 +313,26 @@ void QColorSpacePrivate::identifyColorSpace()
}
}
break;
+ case QColorSpace::Primaries::Bt2020:
+ if (transferFunction == QColorSpace::TransferFunction::Bt2020) {
+ namedColorSpace = QColorSpace::Bt2020;
+ if (description.isEmpty())
+ description = QStringLiteral("BT.2020");
+ return;
+ }
+ if (transferFunction == QColorSpace::TransferFunction::St2084) {
+ namedColorSpace = QColorSpace::Bt2100Pq;
+ if (description.isEmpty())
+ description = QStringLiteral("BT.2100(PQ)");
+ return;
+ }
+ if (transferFunction == QColorSpace::TransferFunction::Hlg) {
+ namedColorSpace = QColorSpace::Bt2100Hlg;
+ if (description.isEmpty())
+ description = QStringLiteral("BT.2100(HLG)");
+ return;
+ }
+ break;
default:
break;
}
@@ -314,7 +355,7 @@ void QColorSpacePrivate::setToXyzMatrix()
}
QColorSpacePrimaries colorSpacePrimaries(primaries);
toXyz = colorSpacePrimaries.toXyzMatrix();
- whitePoint = QColorVector(colorSpacePrimaries.whitePoint);
+ whitePoint = QColorVector::fromXYChromaticity(colorSpacePrimaries.whitePoint);
chad = QColorMatrix::chromaticAdaptation(whitePoint);
toXyz = chad * toXyz;
}
@@ -337,7 +378,7 @@ void QColorSpacePrivate::setTransferFunctionTable(const QList<uint16_t> &transfe
} else if (curve.isSRgb()) {
transferFunction = QColorSpace::TransferFunction::SRgb;
}
- trc[0].m_type = QColorTrc::Type::Function;
+ trc[0].m_type = QColorTrc::Type::ParameterizedFunction;
trc[0].m_fun = curve;
} else {
trc[0].m_type = QColorTrc::Type::Table;
@@ -363,21 +404,21 @@ void QColorSpacePrivate::setTransferFunctionTables(const QList<uint16_t> &redTra
transferFunction = QColorSpace::TransferFunction::Custom;
QColorTransferFunction curve;
if (redTable.asColorTransferFunction(&curve)) {
- trc[0].m_type = QColorTrc::Type::Function;
+ trc[0].m_type = QColorTrc::Type::ParameterizedFunction;
trc[0].m_fun = curve;
} else {
trc[0].m_type = QColorTrc::Type::Table;
trc[0].m_table = redTable;
}
if (greenTable.asColorTransferFunction(&curve)) {
- trc[1].m_type = QColorTrc::Type::Function;
+ trc[1].m_type = QColorTrc::Type::ParameterizedFunction;
trc[1].m_fun = curve;
} else {
trc[1].m_type = QColorTrc::Type::Table;
trc[1].m_table = greenTable;
}
if (blueTable.asColorTransferFunction(&curve)) {
- trc[2].m_type = QColorTrc::Type::Function;
+ trc[2].m_type = QColorTrc::Type::ParameterizedFunction;
trc[2].m_fun = curve;
} else {
trc[2].m_type = QColorTrc::Type::Table;
@@ -390,27 +431,34 @@ void QColorSpacePrivate::setTransferFunction()
{
switch (transferFunction) {
case QColorSpace::TransferFunction::Linear:
- trc[0].m_type = QColorTrc::Type::Function;
- trc[0].m_fun = QColorTransferFunction();
+ trc[0] = QColorTransferFunction();
if (qFuzzyIsNull(gamma))
gamma = 1.0f;
break;
case QColorSpace::TransferFunction::Gamma:
- trc[0].m_type = QColorTrc::Type::Function;
- trc[0].m_fun = QColorTransferFunction::fromGamma(gamma);
+ trc[0] = QColorTransferFunction::fromGamma(gamma);
break;
case QColorSpace::TransferFunction::SRgb:
- trc[0].m_type = QColorTrc::Type::Function;
- trc[0].m_fun = QColorTransferFunction::fromSRgb();
+ trc[0] = QColorTransferFunction::fromSRgb();
if (qFuzzyIsNull(gamma))
gamma = 2.31f;
break;
case QColorSpace::TransferFunction::ProPhotoRgb:
- trc[0].m_type = QColorTrc::Type::Function;
- trc[0].m_fun = QColorTransferFunction::fromProPhotoRgb();
+ trc[0] = QColorTransferFunction::fromProPhotoRgb();
if (qFuzzyIsNull(gamma))
gamma = 1.8f;
break;
+ case QColorSpace::TransferFunction::Bt2020:
+ trc[0] = QColorTransferFunction::fromBt2020();
+ if (qFuzzyIsNull(gamma))
+ gamma = 2.1f;
+ break;
+ case QColorSpace::TransferFunction::St2084:
+ trc[0] = QColorTransferGenericFunction::pq();
+ break;
+ case QColorSpace::TransferFunction::Hlg:
+ trc[0] = QColorTransferGenericFunction::hlg();
+ break;
case QColorSpace::TransferFunction::Custom:
break;
default:
@@ -448,11 +496,13 @@ QColorTransform QColorSpacePrivate::transformationToXYZ() const
transform.d = ptr;
ptr->colorSpaceIn = this;
ptr->colorSpaceOut = this;
- // Convert to XYZ relative to our white point, not the regular D50 white point.
if (isThreeComponentMatrix())
- ptr->colorMatrix = QColorMatrix::chromaticAdaptation(whitePoint).inverted() * toXyz;
+ ptr->colorMatrix = toXyz;
else
ptr->colorMatrix = QColorMatrix::identity();
+ // Convert to XYZ relative to our white point, not the regular D50 white point.
+ if (!chad.isNull())
+ ptr->colorMatrix = chad.inverted() * ptr->colorMatrix;
return transform;
}
@@ -526,6 +576,13 @@ void QColorSpacePrivate::clearElementListProcessingForEdit()
\l{http://www.color.org/chardata/rgb/DCIP3.xalter}{ICC registration of DCI-P3}
\value ProPhotoRgb The Pro Photo RGB color space, also known as ROMM RGB is a very wide gamut color space.
\l{http://www.color.org/chardata/rgb/rommrgb.xalter}{ICC registration of ROMM RGB}
+ \value [since 6.8] Bt2020 BT.2020, also known as Rec.2020 is a basic colorspace of HDR TVs.
+ \l{http://www.color.org/chardata/rgb/BT2020.xalter}{ICC registration of BT.2020}
+ \value [since 6.8] Bt2100Pq BT.2100(PQ), also known as Rec.2100 or HDR10 is an HDR encoding with the same
+ primaries as Bt2020 but using the Perceptual Quantizer transfer function.
+ \l{http://www.color.org/chardata/rgb/BT2100.xalter}{ICC registration of BT.2100}
+ \value [since 6.8] Bt2100Hlg BT.2100 (HLG) is an HDR encoding with the same
+ primaries as Bt2020 but using the Hybrid Log-Gamma transfer function.
*/
/*!
@@ -538,6 +595,7 @@ void QColorSpacePrivate::clearElementListProcessingForEdit()
\value AdobeRgb The Adobe RGB primaries
\value DciP3D65 The DCI-P3 primaries with the D65 whitepoint
\value ProPhotoRgb The ProPhoto RGB primaries with the D50 whitepoint
+ \value [since 6.8] Bt2020 The BT.2020 primaries with a D65 whitepoint
*/
/*!
@@ -550,6 +608,10 @@ void QColorSpacePrivate::clearElementListProcessingForEdit()
\value Gamma A transfer function that is a real gamma curve based on the value of gamma()
\value SRgb The sRGB transfer function, composed of linear and gamma parts
\value ProPhotoRgb The ProPhoto RGB transfer function, composed of linear and gamma parts
+ \value [since 6.8] Bt2020 The BT.2020 transfer function, composited of linear and gamma parts
+ \value [since 6.8] St2084 The SMPTE ST 2084 transfer function, also known Perceptual Quantizer(PQ).
+ \value [since 6.8] Hlg The Hybrid log-gamma transfer function.
+
*/
/*!
@@ -592,7 +654,7 @@ void QColorSpacePrivate::clearElementListProcessingForEdit()
*/
QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
{
- if (namedColorSpace < QColorSpace::SRgb || namedColorSpace > QColorSpace::ProPhotoRgb) {
+ if (namedColorSpace < QColorSpace::SRgb || namedColorSpace > QColorSpace::Bt2100Hlg) {
qWarning() << "QColorSpace attempted constructed from invalid QColorSpace::NamedColorSpace: " << int(namedColorSpace);
return;
}
@@ -940,9 +1002,10 @@ void QColorSpace::setPrimaries(const QPointF &whitePoint, const QPointF &redPoin
return;
}
QColorMatrix toXyz = primaries.toXyzMatrix();
- QColorMatrix chad = QColorMatrix::chromaticAdaptation(QColorVector(whitePoint));
+ QColorMatrix chad = QColorMatrix::chromaticAdaptation(QColorVector::fromXYChromaticity(whitePoint));
toXyz = chad * toXyz;
- if (QColorVector(primaries.whitePoint) == d_ptr->whitePoint && toXyz == d_ptr->toXyz && chad == d_ptr->chad)
+ if (QColorVector::fromXYChromaticity(primaries.whitePoint) == d_ptr->whitePoint
+ && toXyz == d_ptr->toXyz && chad == d_ptr->chad)
return;
detach();
if (d_ptr->transformModel == TransformModel::ElementListProcessing)
@@ -953,7 +1016,7 @@ void QColorSpace::setPrimaries(const QPointF &whitePoint, const QPointF &redPoin
d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
d_ptr->toXyz = toXyz;
d_ptr->chad = chad;
- d_ptr->whitePoint = QColorVector(primaries.whitePoint);
+ d_ptr->whitePoint = QColorVector::fromXYChromaticity(primaries.whitePoint);
d_ptr->identifyColorSpace();
}
@@ -980,7 +1043,7 @@ void QColorSpace::setWhitePoint(const QPointF &whitePoint)
d_ptr = new QColorSpacePrivate(whitePoint, TransferFunction::Custom, 0.0f);
return;
}
- if (QColorVector(whitePoint) == d_ptr->whitePoint)
+ if (QColorVector::fromXYChromaticity(whitePoint) == d_ptr->whitePoint)
return;
detach();
if (d_ptr->transformModel == TransformModel::ElementListProcessing)
@@ -991,7 +1054,7 @@ void QColorSpace::setWhitePoint(const QPointF &whitePoint)
// An RGB color model stays RGB, a gray stays gray, but an undefined one can now be considered gray
if (d_ptr->colorModel == QColorSpace::ColorModel::Undefined)
d_ptr->colorModel = QColorSpace::ColorModel::Gray;
- QColorVector wXyz(whitePoint);
+ QColorVector wXyz(QColorVector::fromXYChromaticity(whitePoint));
if (d_ptr->transformModel == QColorSpace::TransformModel::ThreeComponentMatrix) {
if (d_ptr->colorModel == QColorSpace::ColorModel::Rgb) {
// Rescale toXyz to new whitepoint
@@ -1128,9 +1191,11 @@ bool QColorSpacePrivate::isValid() const noexcept
if (colorModel == QColorSpace::ColorModel::Gray) {
if (!trc[0].isValid())
return false;
- } else {
+ } else if (colorModel == QColorSpace::ColorModel::Rgb){
if (!trc[0].isValid() || !trc[1].isValid() || !trc[2].isValid())
return false;
+ } else {
+ return false;
}
return true;
}
@@ -1418,13 +1483,16 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
if (colorSpace.d_ptr) {
if (colorSpace.d_ptr->namedColorSpace)
dbg << colorSpace.d_ptr->namedColorSpace << ", ";
+ else
+ dbg << colorSpace.colorModel() << ", ";
if (!colorSpace.isValid()) {
dbg << "Invalid";
if (!colorSpace.d_ptr->iccProfile.isEmpty())
dbg << " with profile data";
} else if (colorSpace.d_ptr->isThreeComponentMatrix()) {
dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction();
- dbg << ", gamma=" << colorSpace.gamma();
+ if (colorSpace.transferFunction() == QColorSpace::TransferFunction::Gamma)
+ dbg << "=" << colorSpace.gamma();
} else {
if (colorSpace.d_ptr->isPcsLab)
dbg << "PCSLab, ";