Add QColorSpace::isValidTarget

To indicate color spaces that can not be used as a target,
but only as a source.

Change-Id: Iae79e3533599c112872d171a2f45178029be89dc
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
Allan Sandfeld Jensen 2024-03-06 11:57:09 +01:00
parent 58f93994d9
commit d89063646e
5 changed files with 47 additions and 15 deletions

View File

@ -5018,7 +5018,7 @@ void QImage::convertToColorSpace(const QColorSpace &colorSpace)
return;
if (!d->colorSpace.isValid())
return;
if (!colorSpace.isValid()) {
if (!colorSpace.isValidTarget()) {
qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
return;
}
@ -5039,8 +5039,14 @@ void QImage::convertToColorSpace(const QColorSpace &colorSpace)
*/
QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace) const
{
if (!d || !d->colorSpace.isValid() || !colorSpace.isValid())
if (!d)
return QImage();
if (!d->colorSpace.isValid())
return QImage();
if (!colorSpace.isValidTarget()) {
qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
return QImage();
}
if (d->colorSpace == colorSpace)
return *this;
QImage image = copy();

View File

@ -544,12 +544,14 @@ void QColorSpacePrivate::clearElementListProcessingForEdit()
Defines the processing model used for color space transforms.
\value ThreeComponentMatrix The transform consist of a matrix calculated from primaries and set of transfer functions for each color channel.
This is very fast and used by all predefined color spaces.
\value ElementListProcessing The transforms are two lists of processing elements that can do many things,
\value ThreeComponentMatrix The transform consist of a matrix calculated from primaries and set of transfer functions
for each color channel. This is very fast and used by all predefined color spaces. Any color space on this form is
reversible and always both valid sources and targets.
\value ElementListProcessing The transforms are one or two lists of processing elements that can do many things,
each list only process either to the connection color space or from it. This is very flexible, but rather
slow, and can only be set by reading ICC profiles (See \l fromIccProfile()). When changing either primaries
or transfer function on a color space on this type it will reset to a ThreeComponentMatrix form.
slow, and can only be set by reading ICC profiles (See \l fromIccProfile()). Since the two lists are
separate a color space on this form can be a valid source, but not necessarily also a valid target. When changing
either primaries or transfer function on a color space on this type it will reset to an empty ThreeComponentMatrix form.
*/
/*!
@ -968,7 +970,12 @@ QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile)
}
/*!
Returns \c true if the color space is valid.
Returns \c true if the color space is valid. For a color space with \c TransformModel::ThreeComponentMatrix
that means both primaries and transfer functions set, and implies isValidTarget().
For a color space with \c TransformModel::ElementListProcessing it means it has a valid source transform, to
check if it also a valid target color space use isValidTarget().
\sa isValidTarget()
*/
bool QColorSpace::isValid() const noexcept
{
@ -977,6 +984,20 @@ bool QColorSpace::isValid() const noexcept
return d_ptr->isValid();
}
/*!
\since 6.8
Returns \c true if the color space is a valid target color space.
*/
bool QColorSpace::isValidTarget() const noexcept
{
if (!d_ptr)
return false;
if (!d_ptr->isThreeComponentMatrix())
return !d_ptr->mBA.isEmpty();
return d_ptr->isValid();
}
/*!
\internal
*/
@ -1148,13 +1169,13 @@ bool QColorSpacePrivate::equals(const QColorSpacePrivate *other) const
*/
QColorTransform QColorSpace::transformationToColorSpace(const QColorSpace &colorspace) const
{
if (!isValid() || !colorspace.isValid())
if (!isValid())
return QColorTransform();
if (*this == colorspace)
return QColorTransform();
if (colorspace.transformModel() == TransformModel::ElementListProcessing && colorspace.d_ptr->mBA.isEmpty()) {
qWarning() << "Attempted transform to from-only colorspace";
if (!colorspace.isValidTarget()) {
qWarning() << "QColorSpace::transformationToColorSpace: colorspace not a valid target";
return QColorTransform();
}

View File

@ -108,6 +108,7 @@ public:
TransformModel transformModel() const noexcept;
void detach();
bool isValid() const noexcept;
bool isValidTarget() const noexcept;
friend inline bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
{ return colorSpace1.equals(colorSpace2); }

View File

@ -558,7 +558,7 @@ void tst_QColorSpace::imageConversionOverNonThreeComponentMatrix()
QFETCH(QColorSpace, fromColorSpace);
QFETCH(QColorSpace, toColorSpace);
QVERIFY(fromColorSpace.isValid());
QVERIFY(toColorSpace.isValid());
QVERIFY(toColorSpace.isValidTarget());
QVERIFY(!fromColorSpace.transformationToColorSpace(toColorSpace).isIdentity());

View File

@ -25,11 +25,15 @@ extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) {
QColorSpace cs2 = cs;
cs2.setDescription("Hello");
bool b = (cs == cs2);
Q_UNUSED(b);
QRgb color = 0xfaf8fa00;
color = trans1.map(color);
QColorTransform trans2 = QColorSpace(QColorSpace::SRgb).transformationToColorSpace(cs);
bool a = (trans1 == trans2);
color = trans2.map(color);
if (cs.isValidTarget()) {
QColorTransform trans2 = QColorSpace(QColorSpace::SRgb).transformationToColorSpace(cs);
bool a = (trans1 == trans2);
Q_UNUSED(a);
color = trans2.map(color);
}
}
return 0;
}