summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/painting/qcolor.cpp226
-rw-r--r--src/gui/painting/qcolor.h10
-rw-r--r--src/gui/painting/qcolortransform.cpp39
-rw-r--r--src/gui/painting/qcolortrc_p.h21
-rw-r--r--tests/auto/gui/painting/qcolor/tst_qcolor.cpp203
-rw-r--r--tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp55
6 files changed, 404 insertions, 150 deletions
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index bb42660cf2..174350d884 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -39,6 +39,7 @@
#include "qcolor.h"
#include "qcolor_p.h"
+#include "qfloat16.h"
#include "qnamespace.h"
#include "qdatastream.h"
#include "qvariant.h"
@@ -494,6 +495,14 @@ static QStringList get_colornames()
with this value, a pixel value will be used that is appropriate for the
underlying pixel format in use.
+ \section1 The Extended RGB Color Model
+
+ The extended RGB color model, also known as the scRGB color space,
+ is the same the RGB color model except it allows values under 0.0,
+ and over 1.0. This makes it possible to represent colors that would
+ otherwise be outside the range of the RGB colorspace but still use
+ the same values for colors inside the RGB colorspace.
+
\section1 The HSV Color Model
The RGB model is hardware-oriented. Its representation is close to
@@ -603,12 +612,13 @@ static QStringList get_colornames()
/*!
\enum QColor::Spec
- The type of color specified, either RGB, HSV, CMYK or HSL.
+ The type of color specified, either RGB, extended RGB, HSV, CMYK or HSL.
\value Rgb
\value Hsv
\value Cmyk
\value Hsl
+ \value ExtendedRgb
\value Invalid
\sa spec(), convertTo()
@@ -778,6 +788,10 @@ QColor::QColor(Spec spec) noexcept
case Hsl:
setHsl(0, 0, 0, 0);
break;
+ case ExtendedRgb:
+ cspec = spec;
+ setRgbF(0, 0, 0, 0);
+ break;
}
}
@@ -1211,6 +1225,17 @@ void QColor::setHsl(int h, int s, int l, int a)
ct.ahsl.pad = 0;
}
+static inline qfloat16 &castF16(quint16 &v)
+{
+ // this works because qfloat16 internally is a quint16
+ return *reinterpret_cast<qfloat16 *>(&v);
+}
+
+static inline const qfloat16 &castF16(const quint16 &v)
+{
+ return *reinterpret_cast<const qfloat16 *>(&v);
+}
+
/*!
Sets the contents pointed to by \a r, \a g, \a b, and \a a, to the red,
green, blue, and alpha-channel (transparency) components of the color's
@@ -1226,18 +1251,27 @@ void QColor::getRgbF(qreal *r, qreal *g, qreal *b, qreal *a) const
if (!r || !g || !b)
return;
- if (cspec != Invalid && cspec != Rgb) {
+ if (cspec == Invalid)
+ return;
+
+ if (cspec != Rgb && cspec != ExtendedRgb) {
toRgb().getRgbF(r, g, b, a);
return;
}
- *r = ct.argb.red / qreal(USHRT_MAX);
- *g = ct.argb.green / qreal(USHRT_MAX);
- *b = ct.argb.blue / qreal(USHRT_MAX);
-
- if (a)
- *a = ct.argb.alpha / qreal(USHRT_MAX);
-
+ if (cspec == Rgb) {
+ *r = ct.argb.red / qreal(USHRT_MAX);
+ *g = ct.argb.green / qreal(USHRT_MAX);
+ *b = ct.argb.blue / qreal(USHRT_MAX);
+ if (a)
+ *a = ct.argb.alpha / qreal(USHRT_MAX);
+ } else {
+ *r = castF16(ct.argbExtended.redF16);
+ *g = castF16(ct.argbExtended.greenF16);
+ *b = castF16(ct.argbExtended.blueF16);
+ if (a)
+ *a = castF16(ct.argbExtended.alphaF16);
+ }
}
/*!
@@ -1274,26 +1308,35 @@ void QColor::getRgb(int *r, int *g, int *b, int *a) const
Sets the color channels of this color to \a r (red), \a g (green),
\a b (blue) and \a a (alpha, transparency).
- All values must be in the range 0.0-1.0.
+ The alpha value must be in the range 0.0-1.0.
+ If any of the other values are outside the range of 0.0-1.0 the
+ color model will be set as \c ExtendedRgb.
\sa rgb(), getRgbF(), setRgb()
*/
void QColor::setRgbF(qreal r, qreal g, qreal b, qreal a)
{
- if (r < qreal(0.0) || r > qreal(1.0)
- || g < qreal(0.0) || g > qreal(1.0)
- || b < qreal(0.0) || b > qreal(1.0)
- || a < qreal(0.0) || a > qreal(1.0)) {
- qWarning("QColor::setRgbF: RGB parameters out of range");
+ if (a < qreal(0.0) || a > qreal(1.0)) {
+ qWarning("QColor::setRgbF: Alpha parameter is out of range");
invalidate();
return;
}
-
+ if (r < qreal(0.0) || r > qreal(1.0) ||
+ g < qreal(0.0) || g > qreal(1.0) ||
+ b < qreal(0.0) || b > qreal(1.0) || cspec == ExtendedRgb) {
+ cspec = ExtendedRgb;
+ castF16(ct.argbExtended.redF16) = qfloat16(r);
+ castF16(ct.argbExtended.greenF16) = qfloat16(g);
+ castF16(ct.argbExtended.blueF16) = qfloat16(b);
+ castF16(ct.argbExtended.alphaF16) = qfloat16(a);
+ ct.argbExtended.pad = 0;
+ return;
+ }
cspec = Rgb;
- ct.argb.alpha = qRound(a * USHRT_MAX);
ct.argb.red = qRound(r * USHRT_MAX);
ct.argb.green = qRound(g * USHRT_MAX);
ct.argb.blue = qRound(b * USHRT_MAX);
+ ct.argb.alpha = qRound(a * USHRT_MAX);
ct.argb.pad = 0;
}
@@ -1421,7 +1464,11 @@ void QColor::setRgb(QRgb rgb) noexcept
\sa setAlpha(), alphaF(), {QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing}
*/
int QColor::alpha() const noexcept
-{ return ct.argb.alpha >> 8; }
+{
+ if (cspec == ExtendedRgb)
+ return qRound(qreal(castF16(ct.argbExtended.alphaF16)) * 255);
+ return ct.argb.alpha >> 8;
+}
/*!
@@ -1434,6 +1481,11 @@ int QColor::alpha() const noexcept
void QColor::setAlpha(int alpha)
{
QCOLOR_INT_RANGE_CHECK("QColor::setAlpha", alpha);
+ if (cspec == ExtendedRgb) {
+ constexpr qreal f = qreal(1.0) / 255;
+ castF16(ct.argbExtended.alphaF16) = alpha * f;
+ return;
+ }
ct.argb.alpha = alpha * 0x101;
}
@@ -1443,7 +1495,11 @@ void QColor::setAlpha(int alpha)
\sa setAlphaF(), alpha(), {QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing}
*/
qreal QColor::alphaF() const noexcept
-{ return ct.argb.alpha / qreal(USHRT_MAX); }
+{
+ if (cspec == ExtendedRgb)
+ return castF16(ct.argbExtended.alphaF16);
+ return ct.argb.alpha / qreal(USHRT_MAX);
+}
/*!
Sets the alpha of this color to \a alpha. qreal alpha is specified in the
@@ -1455,6 +1511,10 @@ qreal QColor::alphaF() const noexcept
void QColor::setAlphaF(qreal alpha)
{
QCOLOR_REAL_RANGE_CHECK("QColor::setAlphaF", alpha);
+ if (cspec == ExtendedRgb) {
+ castF16(ct.argbExtended.alphaF16) = alpha;
+ return;
+ }
qreal tmp = alpha * USHRT_MAX;
ct.argb.alpha = qRound(tmp);
}
@@ -1550,25 +1610,29 @@ void QColor::setBlue(int blue)
*/
qreal QColor::redF() const noexcept
{
- if (cspec != Invalid && cspec != Rgb)
- return toRgb().redF();
- return ct.argb.red / qreal(USHRT_MAX);
+ if (cspec == Rgb || cspec == Invalid)
+ return ct.argb.red / qreal(USHRT_MAX);
+ if (cspec == ExtendedRgb)
+ return castF16(ct.argbExtended.redF16);
+
+ return toRgb().redF();
}
/*!
- Sets the red color component of this color to \a red. Float components
- are specified in the range 0.0-1.0.
+ Sets the red color component of this color to \a red. If \a red lies outside
+ the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb.
\sa redF(), red(), setRgbF()
*/
void QColor::setRedF(qreal red)
{
- QCOLOR_REAL_RANGE_CHECK("QColor::setRedF", red);
- if (cspec != Rgb)
- setRgbF(red, greenF(), blueF(), alphaF());
- else
+ if (cspec == Rgb && red >= qreal(0.0) && red <= qreal(1.0))
ct.argb.red = qRound(red * USHRT_MAX);
+ else if (cspec == ExtendedRgb)
+ castF16(ct.argbExtended.redF16) = red;
+ else
+ setRgbF(red, greenF(), blueF(), alphaF());
}
/*!
@@ -1578,25 +1642,29 @@ void QColor::setRedF(qreal red)
*/
qreal QColor::greenF() const noexcept
{
- if (cspec != Invalid && cspec != Rgb)
- return toRgb().greenF();
- return ct.argb.green / qreal(USHRT_MAX);
+ if (cspec == Rgb || cspec == Invalid)
+ return ct.argb.green / qreal(USHRT_MAX);
+ if (cspec == ExtendedRgb)
+ return castF16(ct.argbExtended.greenF16);
+
+ return toRgb().greenF();
}
/*!
- Sets the green color component of this color to \a green. Float components
- are specified in the range 0.0-1.0.
+ Sets the green color component of this color to \a green. If \a green lies outside
+ the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb.
\sa greenF(), green(), setRgbF()
*/
void QColor::setGreenF(qreal green)
{
- QCOLOR_REAL_RANGE_CHECK("QColor::setGreenF", green);
- if (cspec != Rgb)
- setRgbF(redF(), green, blueF(), alphaF());
- else
+ if (cspec == Rgb && green >= qreal(0.0) && green <= qreal(1.0))
ct.argb.green = qRound(green * USHRT_MAX);
+ else if (cspec == ExtendedRgb)
+ castF16(ct.argbExtended.greenF16) = green;
+ else
+ setRgbF(redF(), green, blueF(), alphaF());
}
/*!
@@ -1606,24 +1674,27 @@ void QColor::setGreenF(qreal green)
*/
qreal QColor::blueF() const noexcept
{
- if (cspec != Invalid && cspec != Rgb)
- return toRgb().blueF();
- return ct.argb.blue / qreal(USHRT_MAX);
+ if (cspec == Rgb || cspec == Invalid)
+ return ct.argb.blue / qreal(USHRT_MAX);
+ if (cspec == ExtendedRgb)
+ return castF16(ct.argbExtended.blueF16);
+
+ return toRgb().blueF();
}
/*!
- Sets the blue color component of this color to \a blue. Float components
- are specified in the range 0.0-1.0.
-
+ Sets the blue color component of this color to \a blue. If \a blue lies outside
+ the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb.
\sa blueF(), blue(), setRgbF()
*/
void QColor::setBlueF(qreal blue)
{
- QCOLOR_REAL_RANGE_CHECK("QColor::setBlueF", blue);
- if (cspec != Rgb)
- setRgbF(redF(), greenF(), blue, alphaF());
- else
+ if (cspec == Rgb && blue >= qreal(0.0) && blue <= qreal(1.0))
ct.argb.blue = qRound(blue * USHRT_MAX);
+ else if (cspec == ExtendedRgb)
+ castF16(ct.argbExtended.blueF16) = blue;
+ else
+ setRgbF(redF(), greenF(), blue, alphaF());
}
/*!
@@ -1933,6 +2004,30 @@ qreal QColor::blackF() const noexcept
}
/*!
+ Create and returns an extended RGB QColor based on this color.
+ \since 5.14
+
+ \sa toRgb, convertTo()
+*/
+QColor QColor::toExtendedRgb() const noexcept
+{
+ if (!isValid() || cspec == ExtendedRgb)
+ return *this;
+ if (cspec != Rgb)
+ return toRgb().toExtendedRgb();
+
+ constexpr qreal f = qreal(1.0) / USHRT_MAX;
+ QColor color;
+ color.cspec = ExtendedRgb;
+ castF16(color.ct.argbExtended.alphaF16) = qfloat16(ct.argb.alpha * f);
+ castF16(color.ct.argbExtended.redF16) = qfloat16(ct.argb.red * f);
+ castF16(color.ct.argbExtended.greenF16) = qfloat16(ct.argb.green * f);
+ castF16(color.ct.argbExtended.blueF16) = qfloat16(ct.argb.blue * f);
+ color.ct.argbExtended.pad = 0;
+ return color;
+}
+
+/*!
Create and returns an RGB QColor based on this color.
\sa fromRgb(), convertTo(), isValid()
@@ -1944,7 +2039,8 @@ QColor QColor::toRgb() const noexcept
QColor color;
color.cspec = Rgb;
- color.ct.argb.alpha = ct.argb.alpha;
+ if (cspec != ExtendedRgb)
+ color.ct.argb.alpha = ct.argb.alpha;
color.ct.argb.pad = 0;
switch (cspec) {
@@ -2066,6 +2162,12 @@ QColor QColor::toRgb() const noexcept
color.ct.argb.blue = qRound((qreal(1.0) - (y * (qreal(1.0) - k) + k)) * USHRT_MAX);
break;
}
+ case ExtendedRgb:
+ color.ct.argb.alpha = qRound(USHRT_MAX * qreal(castF16(ct.argbExtended.alphaF16)));
+ color.ct.argb.red = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.redF16)), qreal(1.0)));
+ color.ct.argb.green = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.greenF16)), qreal(1.0)));
+ color.ct.argb.blue = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.blueF16)), qreal(1.0)));
+ break;
default:
break;
}
@@ -2238,6 +2340,8 @@ QColor QColor::convertTo(QColor::Spec colorSpec) const noexcept
switch (colorSpec) {
case Rgb:
return toRgb();
+ case ExtendedRgb:
+ return toExtendedRgb();
case Hsv:
return toHsv();
case Cmyk:
@@ -2317,20 +2421,32 @@ QColor QColor::fromRgb(int r, int g, int b, int a)
color values, \a r (red), \a g (green), \a b (blue), and \a a
(alpha-channel, i.e. transparency).
- All the values must be in the range 0.0-1.0.
+ The alpha value must be in the range 0.0-1.0.
+ If any of the other values are outside the range of 0.0-1.0 the
+ color model will be set as \c ExtendedRgb.
\sa fromRgb(), fromRgba64(), toRgb(), isValid()
*/
QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a)
{
- if (r < qreal(0.0) || r > qreal(1.0)
- || g < qreal(0.0) || g > qreal(1.0)
- || b < qreal(0.0) || b > qreal(1.0)
- || a < qreal(0.0) || a > qreal(1.0)) {
- qWarning("QColor::fromRgbF: RGB parameters out of range");
+ if (a < qreal(0.0) || a > qreal(1.0)) {
+ qWarning("QColor::fromRgbF: Alpha parameter out of range");
return QColor();
}
+ if (r < qreal(0.0) || r > qreal(1.0)
+ || g < qreal(0.0) || g > qreal(1.0)
+ || b < qreal(0.0) || b > qreal(1.0)) {
+ QColor color;
+ color.cspec = ExtendedRgb;
+ castF16(color.ct.argbExtended.alphaF16) = qfloat16(a);
+ castF16(color.ct.argbExtended.redF16) = qfloat16(r);
+ castF16(color.ct.argbExtended.greenF16) = qfloat16(g);
+ castF16(color.ct.argbExtended.blueF16) = qfloat16(b);
+ color.ct.argbExtended.pad = 0;
+ return color;
+ }
+
QColor color;
color.cspec = Rgb;
color.ct.argb.alpha = qRound(a * USHRT_MAX);
@@ -2885,6 +3001,8 @@ QDebug operator<<(QDebug dbg, const QColor &c)
dbg.nospace() << "QColor(Invalid)";
else if (c.spec() == QColor::Rgb)
dbg.nospace() << "QColor(ARGB " << c.alphaF() << ", " << c.redF() << ", " << c.greenF() << ", " << c.blueF() << ')';
+ else if (c.spec() == QColor::ExtendedRgb)
+ dbg.nospace() << "QColor(Ext. ARGB " << c.alphaF() << ", " << c.redF() << ", " << c.greenF() << ", " << c.blueF() << ')';
else if (c.spec() == QColor::Hsv)
dbg.nospace() << "QColor(AHSV " << c.alphaF() << ", " << c.hueF() << ", " << c.saturationF() << ", " << c.valueF() << ')';
else if (c.spec() == QColor::Cmyk)
diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h
index cbc8b98f9c..77b2d43c40 100644
--- a/src/gui/painting/qcolor.h
+++ b/src/gui/painting/qcolor.h
@@ -64,7 +64,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QColor &);
class Q_GUI_EXPORT QColor
{
public:
- enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl };
+ enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl, ExtendedRgb };
enum NameFormat { HexRgb, HexArgb };
inline QColor() noexcept;
@@ -198,6 +198,7 @@ public:
QColor toHsv() const noexcept;
QColor toCmyk() const noexcept;
QColor toHsl() const noexcept;
+ QColor toExtendedRgb() const noexcept;
Q_REQUIRED_RESULT QColor convertTo(Spec colorSpec) const noexcept;
@@ -275,6 +276,13 @@ private:
ushort lightness;
ushort pad;
} ahsl;
+ struct {
+ ushort alphaF16;
+ ushort redF16;
+ ushort greenF16;
+ ushort blueF16;
+ ushort pad;
+ } argbExtended;
ushort array[5];
} ct;
diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp
index b677c4b36b..c723e12f8a 100644
--- a/src/gui/painting/qcolortransform.cpp
+++ b/src/gui/painting/qcolortransform.cpp
@@ -204,19 +204,36 @@ QColor QColorTransform::map(const QColor &color) const
if (!d_ptr)
return color;
Q_D(const QColorTransform);
- QColorVector c = { (float)color.redF(), (float)color.greenF(), (float)color.blueF() };
- c.x = d->colorSpaceIn->trc[0].apply(c.x);
- c.y = d->colorSpaceIn->trc[1].apply(c.y);
- c.z = d->colorSpaceIn->trc[2].apply(c.z);
+ QColor clr = color;
+ if (color.spec() != QColor::ExtendedRgb || color.spec() != QColor::Rgb)
+ clr = clr.toRgb();
+
+ QColorVector c = { (float)clr.redF(), (float)clr.greenF(), (float)clr.blueF() };
+ if (clr.spec() == QColor::ExtendedRgb) {
+ c.x = d->colorSpaceIn->trc[0].applyExtended(c.x);
+ c.y = d->colorSpaceIn->trc[1].applyExtended(c.y);
+ c.z = d->colorSpaceIn->trc[2].applyExtended(c.z);
+ } else {
+ c.x = d->colorSpaceIn->trc[0].apply(c.x);
+ c.y = d->colorSpaceIn->trc[1].apply(c.y);
+ c.z = d->colorSpaceIn->trc[2].apply(c.z);
+ }
c = d->colorMatrix.map(c);
- if (d_ptr->colorSpaceOut->lutsGenerated.loadAcquire()) {
- c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x);
- c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y);
- c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z);
+ bool inGamut = c.x >= 0.0f && c.x <= 1.0f && c.y >= 0.0f && c.y <= 1.0f && c.z >= 0.0f && c.z <= 1.0f;
+ if (inGamut) {
+ if (d_ptr->colorSpaceOut->lutsGenerated.loadAcquire()) {
+ c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x);
+ c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y);
+ c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z);
+ } else {
+ c.x = d->colorSpaceOut->trc[0].applyInverse(c.x);
+ c.y = d->colorSpaceOut->trc[1].applyInverse(c.y);
+ c.z = d->colorSpaceOut->trc[2].applyInverse(c.z);
+ }
} else {
- c.x = d->colorSpaceOut->trc[0].applyInverse(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverse(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverse(c.z);
+ c.x = d->colorSpaceOut->trc[0].applyInverseExtended(c.x);
+ c.y = d->colorSpaceOut->trc[1].applyInverseExtended(c.y);
+ c.z = d->colorSpaceOut->trc[2].applyInverseExtended(c.z);
}
QColor out;
out.setRgbF(c.x, c.y, c.z, color.alphaF());
diff --git a/src/gui/painting/qcolortrc_p.h b/src/gui/painting/qcolortrc_p.h
index 3a649f3756..3ef9d442fc 100644
--- a/src/gui/painting/qcolortrc_p.h
+++ b/src/gui/painting/qcolortrc_p.h
@@ -91,7 +91,16 @@ public:
return m_fun.apply(x);
return x;
}
-
+ float applyExtended(float x) const
+ {
+ if (x >= 0.0f && x <= 1.0f)
+ return apply(x);
+ if (m_type == Type::Function)
+ return std::copysign(m_fun.apply(std::abs(x)), x);
+ if (m_type == Type::Table)
+ return x < 0.0f ? 0.0f : 1.0f;
+ return x;
+ }
float applyInverse(float x) const
{
if (m_type == Type::Table)
@@ -100,6 +109,16 @@ public:
return m_fun.inverted().apply(x);
return x;
}
+ float applyInverseExtended(float x) const
+ {
+ if (x >= 0.0f && x <= 1.0f)
+ return applyInverse(x);
+ if (m_type == Type::Function)
+ return std::copysign(applyInverse(x), x);
+ if (m_type == Type::Table)
+ return x < 0.0f ? 0.0f : 1.0f;
+ return x;
+ }
friend inline bool operator!=(const QColorTrc &o1, const QColorTrc &o2);
friend inline bool operator==(const QColorTrc &o1, const QColorTrc &o2);
diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp
index 13d0618bd9..4d92bdd382 100644
--- a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp
+++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp
@@ -70,6 +70,7 @@ private slots:
void setBlue();
void setRgb();
+ void setRgbF();
void setRgba();
void setHsv();
void setCmyk();
@@ -187,28 +188,28 @@ void tst_QColor::getSetCheck()
// void QColor::setRedF(qreal)
obj1.setRedF(0.0);
QCOMPARE(obj1.redF(), qreal(0.0));
- obj1.setRedF(-0.2);
- QCOMPARE(obj1.redF(), qreal(0.0)); // range<0.0, 1.0
- obj1.setRedF(1.1);
- QCOMPARE(obj1.redF(), qreal(1.0)); // range<0.0, 1.0
+ obj1.setRedF(-0.25);
+ QCOMPARE(obj1.redF(), qreal(-0.25));
+ obj1.setRedF(1.25);
+ QCOMPARE(obj1.redF(), qreal(1.25));
// qreal QColor::greenF()
// void QColor::setGreenF(qreal)
obj1.setGreenF(0.0);
QCOMPARE(obj1.greenF(), qreal(0.0));
- obj1.setGreenF(-0.2);
- QCOMPARE(obj1.greenF(), qreal(0.0)); // range<0.0, 1.0
- obj1.setGreenF(1.1);
- QCOMPARE(obj1.greenF(), qreal(1.0)); // range<0.0, 1.0
+ obj1.setGreenF(-0.25);
+ QCOMPARE(obj1.greenF(), qreal(-0.25));
+ obj1.setGreenF(1.5);
+ QCOMPARE(obj1.greenF(), qreal(1.5));
// qreal QColor::blueF()
// void QColor::setBlueF(qreal)
obj1.setBlueF(0.0);
QCOMPARE(obj1.blueF(), qreal(0.0));
- obj1.setBlueF(-0.2);
- QCOMPARE(obj1.blueF(), qreal(0.0)); // range<0.0, 1.0
- obj1.setBlueF(1.1);
- QCOMPARE(obj1.blueF(), qreal(1.0)); // range<0.0, 1.0
+ obj1.setBlueF(-0.5);
+ QCOMPARE(obj1.blueF(), qreal(-0.5));
+ obj1.setBlueF(2.0);
+ QCOMPARE(obj1.blueF(), qreal(2.0));
// QRgb QColor::rgba()
// void QColor::setRgba(QRgb)
@@ -677,30 +678,81 @@ void tst_QColor::setRgb()
{
QColor color;
- for (int A = 0; A <= USHRT_MAX; ++A) {
- {
- // 0-255
- int a = A >> 8;
- QRgb rgb = qRgba(0, 0, 0, a);
+ for (int a = 0; a <= 255; ++a) {
+ QRgb rgb = qRgba(0, 0, 0, a);
- color.setRgb(0, 0, 0, a);
- QCOMPARE(color.alpha(), a);
- QCOMPARE(color.rgb(), qRgb(0, 0, 0));
+ color.setRgb(0, 0, 0, a);
+ QCOMPARE(color.alpha(), a);
+ QCOMPARE(color.rgb(), qRgb(0, 0, 0));
- color.setRgb(rgb);
- QCOMPARE(color.alpha(), 255);
- QCOMPARE(color.rgb(), qRgb(0, 0, 0));
+ color.setRgb(rgb);
+ QCOMPARE(color.alpha(), 255);
+ QCOMPARE(color.rgb(), qRgb(0, 0, 0));
- int r, g, b, a2;
- color.setRgb(0, 0, 0, a);
- color.getRgb(&r, &g, &b, &a2);
- QCOMPARE(a2, a);
+ int r, g, b, a2;
+ color.setRgb(0, 0, 0, a);
+ color.getRgb(&r, &g, &b, &a2);
+ QCOMPARE(a2, a);
- QColor c(0, 0, 0);
- c.setAlpha(a);
- QCOMPARE(c.alpha(), a);
- }
+ QColor c(0, 0, 0);
+ c.setAlpha(a);
+ QCOMPARE(c.alpha(), a);
+ }
+ for (int r = 0; r <= 255; ++r) {
+ QRgb rgb = qRgb(r, 0, 0);
+
+ color.setRgb(r, 0, 0);
+ QCOMPARE(color.red(), r);
+ QCOMPARE(color.rgb(), rgb);
+
+ color.setRgb(rgb);
+ QCOMPARE(color.red(), r);
+ QCOMPARE(color.rgb(), rgb);
+
+ int r2, g, b, a;
+ color.getRgb(&r2, &g, &b, &a);
+ QCOMPARE(r2, r);
+ }
+
+ for (int g = 0; g <= 255; ++g) {
+ QRgb rgb = qRgb(0, g, 0);
+
+ color.setRgb(0, g, 0);
+ QCOMPARE(color.green(), g);
+ QCOMPARE(color.rgb(), rgb);
+
+ color.setRgb(rgb);
+ QCOMPARE(color.green(), g);
+ QCOMPARE(color.rgb(), rgb);
+
+ int r, g2, b, a;
+ color.getRgb(&r, &g2, &b, &a);
+ QCOMPARE(g2, g);
+ }
+
+ for (int b = 0; b <= 255; ++b) {
+ QRgb rgb = qRgb(0, 0, b);
+
+ color.setRgb(0, 0, b);
+ QCOMPARE(color.blue(), b);
+ QCOMPARE(color.rgb(), rgb);
+
+ color.setRgb(rgb);
+ QCOMPARE(color.blue(), b);
+ QCOMPARE(color.rgb(), rgb);
+
+ int r, g, b2, a;
+ color.getRgb(&r, &g, &b2, &a);
+ QCOMPARE(b2, b);
+ }
+}
+
+void tst_QColor::setRgbF()
+{
+ QColor color;
+
+ for (int A = 0; A <= USHRT_MAX; ++A) {
{
// 0.0-1.0
qreal a = A / qreal(USHRT_MAX);
@@ -720,24 +772,6 @@ void tst_QColor::setRgb()
for (int R = 0; R <= USHRT_MAX; ++R) {
{
- // 0-255
- int r = R >> 8;
- QRgb rgb = qRgb(r, 0, 0);
-
- color.setRgb(r, 0, 0);
- QCOMPARE(color.red(), r);
- QCOMPARE(color.rgb(), rgb);
-
- color.setRgb(rgb);
- QCOMPARE(color.red(), r);
- QCOMPARE(color.rgb(), rgb);
-
- int r2, g, b, a;
- color.getRgb(&r2, &g, &b, &a);
- QCOMPARE(r2, r);
- }
-
- {
// 0.0-1.0
qreal r = R / qreal(USHRT_MAX);
color.setRgbF(r, 0.0, 0.0);
@@ -751,24 +785,6 @@ void tst_QColor::setRgb()
for (int G = 0; G <= USHRT_MAX; ++G) {
{
- // 0-255
- int g = G >> 8;
- QRgb rgb = qRgb(0, g, 0);
-
- color.setRgb(0, g, 0);
- QCOMPARE(color.green(), g);
- QCOMPARE(color.rgb(), rgb);
-
- color.setRgb(rgb);
- QCOMPARE(color.green(), g);
- QCOMPARE(color.rgb(), rgb);
-
- int r, g2, b, a;
- color.getRgb(&r, &g2, &b, &a);
- QCOMPARE(g2, g);
- }
-
- {
// 0.0-1.0
qreal g = G / qreal(USHRT_MAX);
color.setRgbF(0.0, g, 0.0);
@@ -782,32 +798,53 @@ void tst_QColor::setRgb()
for (int B = 0; B <= USHRT_MAX; ++B) {
{
- // 0-255
- int b = B >> 8;
- QRgb rgb = qRgb(0, 0, b);
+ // 0.0-1.0
+ qreal b = B / qreal(USHRT_MAX);
+ color.setRgbF(0.0, 0.0, b);
+ QCOMPARE(color.blueF(), b);
- color.setRgb(0, 0, b);
- QCOMPARE(color.blue(), b);
- QCOMPARE(color.rgb(), rgb);
+ qreal r, g, b2, a;
+ color.getRgbF(&r, &g, &b2, &a);
+ QCOMPARE(b2, b);
+ }
+ }
- color.setRgb(rgb);
- QCOMPARE(color.blue(), b);
- QCOMPARE(color.rgb(), rgb);
+ for (int R = -128; R <= 512; ++R) {
+ {
+ // extended RGB
+ qreal r = R / qreal(256);
+ color.setRgbF(r, 0.0, 0.0);
+ QCOMPARE(qfloat16(color.redF()), qfloat16(r));
- int r, g, b2, a;
- color.getRgb(&r, &g, &b2, &a);
- QCOMPARE(b2, b);
+ qreal r2, g, b, a;
+ color.getRgbF(&r2, &g, &b, &a);
+ QCOMPARE(qfloat16(r2), qfloat16(r));
}
+ }
+ for (int G = -128; G <= 512; ++G) {
{
- // 0.0-1.0
- qreal b = B / qreal(USHRT_MAX);
+ // extended RGB
+ qreal g = G / qreal(256);
+ color.setRgbF(0.0, g, 0.0);
+ QCOMPARE(qfloat16(color.greenF()), qfloat16(g));
+
+ qreal r, g2, b, a;
+ color.getRgbF(&r, &g2, &b, &a);
+ QCOMPARE(qfloat16(g2), qfloat16(g));
+ }
+ }
+
+ for (int B = -128; B <= 512; ++B) {
+ {
+ // extended RGB
+ qreal b = B / qreal(256);
color.setRgbF(0.0, 0.0, b);
- QCOMPARE(color.blueF(), b);
+ QCOMPARE(qfloat16(color.blueF()), qfloat16(b));
qreal r, g, b2, a;
color.getRgbF(&r, &g, &b2, &a);
- QCOMPARE(b2, b);
+ QCOMPARE(qfloat16(b2), qfloat16(b));
}
}
}
diff --git a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp
index 9bd4b75443..35bca58854 100644
--- a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp
+++ b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp
@@ -57,6 +57,8 @@ private slots:
void imageConversion();
void loadImage();
+
+ void gamut();
};
tst_QColorSpace::tst_QColorSpace()
@@ -232,6 +234,59 @@ void tst_QColorSpace::loadImage()
// Test the iccProfile getter returns the ICC profile from the image
// which since we didn't write it, isn't identical to our defaults.
QVERIFY(defaultProPhotoRgb.iccProfile() != image.colorSpace().iccProfile());
+
+ QColorTransform transform = image.colorSpace().transformationToColorSpace(QColorSpace::SRgb);
+ qreal maxRed = 0;
+ qreal maxBlue = 0;
+ qreal maxRed2 = 0;
+ qreal maxBlue2 = 0;
+ for (int y = 0; y < image.height(); ++y) {
+ for (int x = 0; x < image.width(); ++x) {
+ QColor p = image.pixelColor(x, y);
+ maxRed = std::max(maxRed, p.redF());
+ maxBlue = std::max(maxBlue, p.blueF());
+ p = transform.map(p);
+ maxRed2 = std::max(maxRed2, p.redF());
+ maxBlue2 = std::max(maxBlue2, p.blueF());
+
+ }
+ }
+ // ProPhotoRgb can be a lot more red and blue than SRgb can, so it will have lower values.
+ QVERIFY(maxRed2 > maxRed);
+ QVERIFY(maxBlue2 > maxBlue);
+}
+
+void tst_QColorSpace::gamut()
+{
+ QColor black = QColor::fromRgbF(0.0, 0.0, 0.0);
+ QColor white = QColor::fromRgbF(1.0, 1.0, 1.0);
+ QColor red = QColor::fromRgbF(1.0, 0.0, 0.0);
+ QColor green = QColor::fromRgbF(0.0, 1.0, 0.0);
+ QColor blue = QColor::fromRgbF(0.0, 0.0, 1.0);
+
+ QColorTransform toAdobeRgb = QColorSpace(QColorSpace::SRgb).transformationToColorSpace(QColorSpace::AdobeRgb);
+
+ QColor tblack = toAdobeRgb.map(black);
+ QColor twhite = toAdobeRgb.map(white);
+ QColor tred = toAdobeRgb.map(red);
+ QColor tgreen = toAdobeRgb.map(green);
+ QColor tblue = toAdobeRgb.map(blue);
+
+ // Black is black
+ QCOMPARE(tblack, black);
+
+ // This white hasn't changed
+ QCOMPARE(twhite, white);
+
+ // Adobe's red and blue gamut corners are the same as sRGB's
+ // So, a color in the red corner, will stay in the red corner
+ // the same for blue, but not for green.
+ QVERIFY(tred.greenF() < 0.001);
+ QVERIFY(tred.blueF() < 0.001);
+ QVERIFY(tblue.redF() < 0.001);
+ QVERIFY(tblue.greenF() < 0.001);
+ QVERIFY(tgreen.redF() > 0.2);
+ QVERIFY(tgreen.blueF() > 0.2);
}
QTEST_MAIN(tst_QColorSpace)