diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-04-15 14:19:48 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-12-10 11:03:12 +0100 |
commit | 48346e8d2df287dd4b7e6d51de491c3bd3020255 (patch) | |
tree | b2db9b6ebd8ded1e239124cd40e30961783193b2 /src | |
parent | 667e5b1210cf8783c5b16445a09f30d14bc83c0f (diff) |
Add colorspace transfer functions based on tables of inputs
This is the most basic way to represent custom transfer functions.
Change-Id: I529fb647ece82c03e85ef77b056d9daf13fe5a61
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/painting/qcolorspace.cpp | 116 | ||||
-rw-r--r-- | src/gui/painting/qcolorspace.h | 6 | ||||
-rw-r--r-- | src/gui/painting/qcolorspace_p.h | 3 | ||||
-rw-r--r-- | src/gui/painting/qcolortransfertable_p.h | 42 |
4 files changed, 144 insertions, 23 deletions
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp index ed25ead262..0a87c35400 100644 --- a/src/gui/painting/qcolorspace.cpp +++ b/src/gui/painting/qcolorspace.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -221,6 +221,29 @@ QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries, setTransferFunction(); } +QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, const QVector<uint16_t> &transferFunctionTable) + : primaries(primaries) + , transferFunction(QColorSpace::TransferFunction::Custom) + , gamma(0) +{ + setTransferFunctionTable(transferFunctionTable); + identifyColorSpace(); + initialize(); +} + +QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries, const QVector<uint16_t> &transferFunctionTable) + : primaries(QColorSpace::Primaries::Custom) + , transferFunction(QColorSpace::TransferFunction::Custom) + , gamma(0) +{ + Q_ASSERT(primaries.areValid()); + toXyz = primaries.toXyzMatrix(); + whitePoint = QColorVector(primaries.whitePoint); + setTransferFunctionTable(transferFunctionTable); + identifyColorSpace(); + initialize(); +} + void QColorSpacePrivate::identifyColorSpace() { switch (primaries) { @@ -298,6 +321,32 @@ void QColorSpacePrivate::setToXyzMatrix() whitePoint = QColorVector(colorSpacePrimaries.whitePoint); } +void QColorSpacePrivate::setTransferFunctionTable(const QVector<uint16_t> &transferFunctionTable) +{ + QColorTransferTable table(transferFunctionTable.size(), transferFunctionTable); + if (!table.isEmpty() && !table.checkValidity()) { + qWarning() << "Invalid transfer function table given to QColorSpace"; + trc[0].m_type = QColorTrc::Type::Uninitialized; + return; + } + transferFunction = QColorSpace::TransferFunction::Custom; + QColorTransferFunction curve; + if (table.asColorTransferFunction(&curve)) { + // Table recognized as a specific curve + if (curve.isLinear()) { + transferFunction = QColorSpace::TransferFunction::Linear; + gamma = 1.0f; + } else if (curve.isSRgb()) { + transferFunction = QColorSpace::TransferFunction::SRgb; + } + trc[0].m_type = QColorTrc::Type::Function; + trc[0].m_fun = curve; + } else { + trc[0].m_type = QColorTrc::Type::Table; + trc[0].m_table = table; + } +} + void QColorSpacePrivate::setTransferFunction() { switch (transferFunction) { @@ -471,6 +520,20 @@ QColorSpace::QColorSpace(QColorSpace::Primaries primaries, float gamma) } /*! + Creates a custom color space with the primaries \a primaries, using a custom transfer function + described by \a transferFunctionTable. + + The table should contain at least 2 values, and contain an monotonically increasing list + of values from 0 to 65535. + + \since 6.1 + */ +QColorSpace::QColorSpace(QColorSpace::Primaries gamut, const QVector<uint16_t> &transferFunctionTable) + : d_ptr(new QColorSpacePrivate(gamut, transferFunctionTable)) +{ +} + +/*! Creates a custom colorspace with a primaries based on the chromaticities of the primary colors \a whitePoint, \a redPoint, \a greenPoint and \a bluePoint, and using the transfer function \a transferFunction and optionally \a gamma. */ @@ -486,6 +549,20 @@ QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint, d_ptr = new QColorSpacePrivate(primaries, transferFunction, gamma); } +/*! + Creates a custom color space with primaries based on the chromaticities of the primary colors \a whitePoint, + \a redPoint, \a greenPoint and \a bluePoint, and using the custom transfer function described by + \a transferFunctionTable. + + \since 6.1 + */ +QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint, + const QPointF &greenPoint, const QPointF &bluePoint, + const QVector<uint16_t> &transferFunctionTable) + : d_ptr(new QColorSpacePrivate({whitePoint, redPoint, greenPoint, bluePoint}, transferFunctionTable)) +{ +} + QColorSpace::~QColorSpace() = default; QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QColorSpacePrivate) @@ -560,6 +637,27 @@ void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunc } /*! + Sets the transfer function to \a transferFunctionTable. + + \since 6.1 + \sa transferFunction() +*/ +void QColorSpace::setTransferFunction(const QVector<uint16_t> &transferFunctionTable) +{ + if (!d_ptr) { + d_ptr = new QColorSpacePrivate(Primaries::Custom, transferFunctionTable); + d_ptr->ref.ref(); + return; + } + detach(); + d_ptr->description.clear(); + d_ptr->setTransferFunctionTable(transferFunctionTable); + d_ptr->gamma = 0; + d_ptr->identifyColorSpace(); + d_ptr->setTransferFunction(); +} + +/*! Returns a copy of this color space, except using the transfer function \a transferFunction and \a gamma. @@ -577,6 +675,22 @@ QColorSpace QColorSpace::withTransferFunction(QColorSpace::TransferFunction tran } /*! + Returns a copy of this color space, except using the transfer function + described by \a transferFunctionTable. + + \since 6.1 + \sa transferFunction(), setTransferFunction() +*/ +QColorSpace QColorSpace::withTransferFunction(const QVector<uint16_t> &transferFunctionTable) const +{ + if (!isValid()) + return *this; + QColorSpace out(*this); + out.setTransferFunction(transferFunctionTable); + return out; +} + +/*! Sets the primaries to those of the \a primariesId set. \sa primaries() diff --git a/src/gui/painting/qcolorspace.h b/src/gui/painting/qcolorspace.h index a53a786233..2d4de4c9a8 100644 --- a/src/gui/painting/qcolorspace.h +++ b/src/gui/painting/qcolorspace.h @@ -86,9 +86,13 @@ public: QColorSpace(NamedColorSpace namedColorSpace); QColorSpace(Primaries primaries, TransferFunction transferFunction, float gamma = 0.0f); QColorSpace(Primaries primaries, float gamma); + QColorSpace(Primaries primaries, const QVector<uint16_t> &transferFunctionTable); QColorSpace(const QPointF &whitePoint, const QPointF &redPoint, const QPointF &greenPoint, const QPointF &bluePoint, TransferFunction transferFunction, float gamma = 0.0f); + QColorSpace(const QPointF &whitePoint, const QPointF &redPoint, + const QPointF &greenPoint, const QPointF &bluePoint, + const QVector<uint16_t> &transferFunctionTable); ~QColorSpace(); QColorSpace(const QColorSpace &colorSpace) noexcept; @@ -110,7 +114,9 @@ public: float gamma() const noexcept; void setTransferFunction(TransferFunction transferFunction, float gamma = 0.0f); + void setTransferFunction(const QVector<uint16_t> &transferFunctionTable); QColorSpace withTransferFunction(TransferFunction transferFunction, float gamma = 0.0f) const; + QColorSpace withTransferFunction(const QVector<uint16_t> &transferFunctionTable) const; void setPrimaries(Primaries primariesId); void setPrimaries(const QPointF &whitePoint, const QPointF &redPoint, diff --git a/src/gui/painting/qcolorspace_p.h b/src/gui/painting/qcolorspace_p.h index da2d3a9c30..9dbedd9e05 100644 --- a/src/gui/painting/qcolorspace_p.h +++ b/src/gui/painting/qcolorspace_p.h @@ -92,7 +92,9 @@ public: QColorSpacePrivate(); QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace); QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction, float gamma); + QColorSpacePrivate(QColorSpace::Primaries primaries, const QVector<uint16_t> &transferFunctionTable); QColorSpacePrivate(const QColorSpacePrimaries &primaries, QColorSpace::TransferFunction transferFunction, float gamma); + QColorSpacePrivate(const QColorSpacePrimaries &primaries, const QVector<uint16_t> &transferFunctionTable); QColorSpacePrivate(const QColorSpacePrivate &other) = default; static const QColorSpacePrivate *get(const QColorSpace &colorSpace) @@ -109,6 +111,7 @@ public: void setToXyzMatrix(); void setTransferFunction(); void identifyColorSpace(); + void setTransferFunctionTable(const QVector<uint16_t> &transferFunctionTable); QColorTransform transformationToColorSpace(const QColorSpacePrivate *out) const; static constexpr QColorSpace::NamedColorSpace Unknown = QColorSpace::NamedColorSpace(0); diff --git a/src/gui/painting/qcolortransfertable_p.h b/src/gui/painting/qcolortransfertable_p.h index fdf68b78da..2812ed5685 100644 --- a/src/gui/painting/qcolortransfertable_p.h +++ b/src/gui/painting/qcolortransfertable_p.h @@ -55,6 +55,8 @@ #include "qcolortransferfunction_p.h" #include <QList> + +#include <algorithm> #include <cmath> QT_BEGIN_NAMESPACE @@ -114,11 +116,11 @@ public: float apply(float x) const { - x = std::min(std::max(x, 0.0f), 1.0f); + x = std::clamp(x, 0.0f, 1.0f); x *= m_tableSize - 1; - uint32_t lo = static_cast<uint32_t>(std::floor(x)); - uint32_t hi = std::min(lo + 1, m_tableSize - 1); - float frac = x - lo; + const uint32_t lo = static_cast<uint32_t>(std::floor(x)); + const uint32_t hi = std::min(lo + 1, m_tableSize); + const float frac = x - lo; if (!m_table16.isEmpty()) return (m_table16[lo] * (1.0f - frac) + m_table16[hi] * frac) * (1.0f/65535.0f); if (!m_table8.isEmpty()) @@ -135,34 +137,30 @@ public: if (x >= 1.0f) return 1.0f; if (!m_table16.isEmpty()) { - float v = x * 65535.0f; - uint32_t i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1; - for ( ; i < m_tableSize; ++i) { - if (m_table16[i] > v) - break; - } + const float v = x * 65535.0f; + uint32_t i = static_cast<uint32_t>(std::floor(resultLargerThan * (m_tableSize - 1))) + 1; + auto it = std::lower_bound(m_table16.cbegin() + i, m_table16.cend(), v); + i = it - m_table16.cbegin(); if (i >= m_tableSize - 1) return 1.0f; - float y1 = m_table16[i - 1]; - float y2 = m_table16[i]; + const float y1 = m_table16[i - 1]; + const float y2 = m_table16[i]; Q_ASSERT(x >= y1 && x < y2); - float fr = (v - y1) / (y2 - y1); + const float fr = (v - y1) / (y2 - y1); return (i + fr) * (1.0f / (m_tableSize - 1)); } if (!m_table8.isEmpty()) { - float v = x * 255.0f; - uint32_t i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1; - for ( ; i < m_tableSize; ++i) { - if (m_table8[i] > v) - break; - } + const float v = x * 255.0f; + uint32_t i = static_cast<uint32_t>(std::floor(resultLargerThan * (m_tableSize - 1))) + 1; + auto it = std::lower_bound(m_table8.cbegin() + i, m_table8.cend(), v); + i = it - m_table8.cbegin(); if (i >= m_tableSize - 1) return 1.0f; - float y1 = m_table8[i - 1]; - float y2 = m_table8[i]; + const float y1 = m_table8[i - 1]; + const float y2 = m_table8[i]; Q_ASSERT(x >= y1 && x < y2); - float fr = (v - y1) / (y2 - y1); + const float fr = (v - y1) / (y2 - y1); return (i + fr) * (1.0f / (m_tableSize - 1)); } return x; |