diff options
author | Thomas Hartmann <Thomas.Hartmann@nokia.com> | 2009-08-24 09:02:27 (GMT) |
---|---|---|
committer | Thomas Hartmann <Thomas.Hartmann@nokia.com> | 2009-08-24 09:06:51 (GMT) |
commit | c0b20c70d4272554d1e39b21bebf80f290dbe026 (patch) | |
tree | 4eca5736c0b609333cd227e029b1f847f59d319d /src/gui | |
parent | 91e1f75992a5fa720ad748d8487a44b5a242ca2d (diff) | |
download | Qt-c0b20c70d4272554d1e39b21bebf80f290dbe026.zip Qt-c0b20c70d4272554d1e39b21bebf80f290dbe026.tar.gz Qt-c0b20c70d4272554d1e39b21bebf80f290dbe026.tar.bz2 |
HSL support for QColor
This patch adds support for the HSL color space to QColor
See discussions on dev mailing list
Reviewed-by: Marco Bubke
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/painting/qcolor.cpp | 453 | ||||
-rw-r--r-- | src/gui/painting/qcolor.h | 32 |
2 files changed, 472 insertions, 13 deletions
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 4e93f04..ef884bd 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -237,6 +237,15 @@ QT_BEGIN_NAMESPACE alpha-channel to feature \l {QColor#Alpha-Blended Drawing}{alpha-blended drawing}. + \section1 The HSL Color Model + + HSL is similar to HSV. Instead of value parameter from HSV, + HSL has the lightness parameter. + The lightness parameter goes from black to color and from color to white. + If you go outside at the night its black or dark gray. At day its colorful but + if you look in a really strong light a things they are going to white and + wash out. + \section1 The CMYK Color Model While the RGB and HSV color models are used for display on @@ -437,6 +446,9 @@ QColor::QColor(Spec spec) case Cmyk: setCmyk(0, 0, 0, 0); break; + case Hsl: + setHsl(0, 0, 0, 0); + break; } } @@ -678,6 +690,113 @@ void QColor::setHsv(int h, int s, int v, int a) } /*! + Sets the contents pointed to by \a h, \a s, \a l, and \a a, to the hue, + saturation, lightness, and alpha-channel (transparency) components of the + color's HSL value. + + These components can be retrieved individually using the hueHslF(), + saturationHslF(), lightnessF() and alphaF() functions. + + \sa setHsl() +*/ +void QColor::getHslF(qreal *h, qreal *s, qreal *l, qreal *a) const +{ + if (!h || !s || !l) + return; + + if (cspec != Invalid && cspec != Hsl) { + toHsl().getHslF(h, s, l, a); + return; + } + + *h = ct.ahsl.hue == USHRT_MAX ? -1.0 : ct.ahsl.hue / 36000.0; + *s = ct.ahsl.saturation / qreal(USHRT_MAX); + *l = ct.ahsl.lightness / qreal(USHRT_MAX); + + if (a) + *a = ct.ahsl.alpha / qreal(USHRT_MAX); +} + +/*! + Sets the contents pointed to by \a h, \a s, \a l, and \a a, to the hue, + saturation, lightness, and alpha-channel (transparency) components of the + color's HSL value. + + These components can be retrieved individually using the hueHsl(), + saturationHsl(), lightness() and alpha() functions. + + \sa setHsl() +*/ +void QColor::getHsl(int *h, int *s, int *l, int *a) const +{ + if (!h || !s || !l) + return; + + if (cspec != Invalid && cspec != Hsl) { + toHsl().getHsl(h, s, l, a); + return; + } + + *h = ct.ahsl.hue == USHRT_MAX ? -1 : ct.ahsl.hue / 100; + *s = ct.ahsl.saturation >> 8; + *l = ct.ahsl.lightness >> 8; + + if (a) + *a = ct.ahsl.alpha >> 8; +} + +/*! + Sets a HSL color lightness; \a h is the hue, \a s is the saturation, \a l is + the lightness and \a a is the alpha component of the HSL color. + + All the values must be in the range 0.0-1.0. + + \sa getHslF(), setHsl() +*/ +void QColor::setHslF(qreal h, qreal s, qreal l, qreal a) +{ + if (((h < 0.0 || h > 1.0) && h != -1.0) + || (s < 0.0 || s > 1.0) + || (l < 0.0 || l > 1.0) + || (a < 0.0 || a > 1.0)) { + qWarning("QColor::setHsvF: HSV parameters out of range"); + return; + } + + cspec = Hsl; + ct.ahsl.alpha = qRound(a * USHRT_MAX); + ct.ahsl.hue = h == -1.0 ? USHRT_MAX : qRound(h * 36000); + ct.ahsl.saturation = qRound(s * USHRT_MAX); + ct.ahsl.lightness = qRound(l * USHRT_MAX); + ct.ahsl.pad = 0; +} + +/*! + Sets a HSL color value; \a h is the hue, \a s is the saturation, \a l is + the lightness and \a a is the alpha component of the HSL color. + + The saturation, value and alpha-channel values must be in the range 0-255, + and the hue value must be greater than -1. + + \sa getHsl(), setHslF() +*/ +void QColor::setHsl(int h, int s, int l, int a) +{ + if (h < -1 || (uint)s > 255 || (uint)l > 255 || (uint)a > 255) { + qWarning("QColor::setHsv: HSV parameters out of range"); + invalidate(); + return; + } + + cspec = Hsl; + ct.ahsl.alpha = a * 0x101; + ct.ahsl.hue = h == -1 ? USHRT_MAX : (h % 360) * 100; + ct.ahsl.saturation = s * 0x101; + ct.ahsl.lightness = l * 0x101; + ct.ahsl.pad = 0; +} + +/*! 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 RGB value. @@ -1082,11 +1201,25 @@ void QColor::setBlueF(qreal blue) /*! Returns the hue color component of this color. - \sa hueF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color + The color is implicitly converted to HSV. + + \sa hsvHue(), hueF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color Model} */ + int QColor::hue() const { + return hsvHue(); +} + +/*! + Returns the hue color component of this color. + + \sa hueF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color + Model} +*/ +int QColor::hsvHue() const +{ if (cspec != Invalid && cspec != Hsv) return toHsv().hue(); return ct.ahsv.hue == USHRT_MAX ? -1 : ct.ahsv.hue / 100; @@ -1095,11 +1228,25 @@ int QColor::hue() const /*! Returns the saturation color component of this color. - \sa saturationF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color + The color is implicitly converted to HSV. + + \sa hsvSaturation(), saturationF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color Model} */ + int QColor::saturation() const { + return hsvSaturation(); +} + +/*! + Returns the saturation color component of this color. + + \sa saturationF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color + Model} +*/ +int QColor::hsvSaturation() const +{ if (cspec != Invalid && cspec != Hsv) return toHsv().saturation(); return ct.ahsv.saturation >> 8; @@ -1121,11 +1268,24 @@ int QColor::value() const /*! Returns the hue color component of this color. - \sa hue(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color + The color is implicitly converted to HSV. + + \sa hsvHueF(), hue(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model} */ qreal QColor::hueF() const { + return hsvHueF(); +} + +/*! + Returns the hue color component of this color. + + \sa hue(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color + Model} +*/ +qreal QColor::hsvHueF() const +{ if (cspec != Invalid && cspec != Hsv) return toHsv().hueF(); return ct.ahsv.hue == USHRT_MAX ? -1.0 : ct.ahsv.hue / 36000.0; @@ -1134,11 +1294,24 @@ qreal QColor::hueF() const /*! Returns the saturation color component of this color. - \sa saturation() getHsvF(), {QColor#The HSV Color Model}{The HSV Color + The color is implicitly converted to HSV. + + \sa hsvSaturationF(), saturation() getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model} */ qreal QColor::saturationF() const { + return hsvSaturationF(); +} + +/*! + Returns the saturation color component of this color. + + \sa saturation() getHsvF(), {QColor#The HSV Color Model}{The HSV Color + Model} +*/ +qreal QColor::hsvSaturationF() const +{ if (cspec != Invalid && cspec != Hsv) return toHsv().saturationF(); return ct.ahsv.saturation / qreal(USHRT_MAX); @@ -1158,6 +1331,79 @@ qreal QColor::valueF() const } /*! + Returns the hue color component of this color. + + \sa hueHslF(), getHsl() +*/ +int QColor::hslHue() const +{ + if (cspec != Invalid && cspec != Hsl) + return toHsl().hslHue(); + return ct.ahsl.hue == USHRT_MAX ? -1 : ct.ahsl.hue / 100; +} + +/*! + Returns the saturation color component of this color. + + \sa saturationF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color + Model} +*/ +int QColor::hslSaturation() const +{ + if (cspec != Invalid && cspec != Hsl) + return toHsl().hslSaturation(); + return ct.ahsl.saturation >> 8; +} + +/*! + Returns the lightness color component of this color. + + \sa lightnessF(), getHsl() +*/ +int QColor::lightness() const +{ + if (cspec != Invalid && cspec != Hsl) + return toHsl().lightness(); + return ct.ahsl.lightness >> 8; +} + +/*! + Returns the hue color component of this color. + + \sa hue(), getHslF() +*/ +qreal QColor::hslHueF() const +{ + if (cspec != Invalid && cspec != Hsl) + return toHsl().hslHueF(); + return ct.ahsl.hue == USHRT_MAX ? -1.0 : ct.ahsl.hue / 36000.0; +} + +/*! + Returns the saturation color component of this color. + + \sa saturationHsl() getHslF() +*/ +qreal QColor::hslSaturationF() const +{ + if (cspec != Invalid && cspec != Hsl) + return toHsl().hslSaturationF(); + return ct.ahsl.saturation / qreal(USHRT_MAX); +} + +/*! + Returns the lightness color component of this color. + + \sa value() getHslF() +*/ +qreal QColor::lightnessF() const +{ + if (cspec != Invalid && cspec != Hsl) + return toHsl().lightnessF(); + return ct.ahsl.lightness / qreal(USHRT_MAX); +} + +/*! Returns the cyan color component of this color. \sa cyanF(), getCmyk(), {QColor#The CMYK Color Model}{The CMYK @@ -1337,6 +1583,53 @@ QColor QColor::toRgb() const } break; } + case Hsl: + { + if (ct.ahsl.saturation == 0 || ct.ahsl.hue == USHRT_MAX) { + // achromatic case + color.ct.argb.red = color.ct.argb.green = color.ct.argb.blue = ct.ahsl.lightness; + } else if (ct.ahsl.lightness == 0) { + // lightness 0 + color.ct.argb.red = color.ct.argb.green = color.ct.argb.blue = 0; + } else { + // chromatic case + const qreal h = ct.ahsl.hue == 36000 ? 0 : ct.ahsl.hue / 36000.; + const qreal s = ct.ahsl.saturation / qreal(USHRT_MAX); + const qreal l = ct.ahsl.lightness / qreal(USHRT_MAX); + + qreal temp2; + if (l < qreal(0.5)) + temp2 = l * (qreal(1.0) + s); + else + temp2 = l + s - (l * s); + + const qreal temp1 = (qreal(2.0) * l) - temp2; + qreal temp3[3] = { h + (qreal(1.0) / qreal(3.0)), + h, + h - (qreal(1.0) / qreal(3.0)) }; + + for (int i = 0; i != 3; ++i) { + if (temp3[i] < qreal(0.0)) + temp3[i] += qreal(1.0); + else if (temp3[i] > qreal(1.0)) + temp3[i] -= qreal(1.0); + + const qreal sixtemp3 = temp3[i] * qreal(6.0); + if (sixtemp3 < qreal(1.0)) + color.ct.array[i+1] = qRound((temp1 + (temp2 - temp1) * sixtemp3) * USHRT_MAX); + else if ((temp3[i] * qreal(2.0)) < qreal(1.0)) + color.ct.array[i+1] = qRound(temp2 * USHRT_MAX); + else if ((temp3[i] * qreal(3.0)) < qreal(2.0)) + color.ct.array[i+1] = qRound((temp1 + (temp2 -temp1) * (qreal(2.0) /qreal(3.0) - temp3[i]) * qreal(6.0)) * USHRT_MAX); + else + color.ct.array[i+1] = qRound(temp1 * USHRT_MAX); + } + color.ct.argb.red = color.ct.argb.red == 1 ? 0 : color.ct.argb.red; + color.ct.argb.green = color.ct.argb.green == 1 ? 0 : color.ct.argb.green; + color.ct.argb.blue = color.ct.argb.blue == 1 ? 0 : color.ct.argb.blue; + } + break; + } case Cmyk: { const qreal c = ct.acmyk.cyan / qreal(USHRT_MAX); @@ -1414,6 +1707,62 @@ QColor QColor::toHsv() const } /*! + Creates and returns an HSL QColor based on this color. + + \sa fromHsl(), convertTo(), isValid() +*/ +QColor QColor::toHsl() const +{ + if (!isValid() || cspec == Hsl) + return *this; + + if (cspec != Rgb) + return toRgb().toHsl(); + + QColor color; + color.cspec = Hsl; + color.ct.ahsl.alpha = ct.argb.alpha; + color.ct.ahsl.pad = 0; + + const qreal r = ct.argb.red / qreal(USHRT_MAX); + const qreal g = ct.argb.green / qreal(USHRT_MAX); + const qreal b = ct.argb.blue / qreal(USHRT_MAX); + const qreal max = Q_MAX_3(r, g, b); + const qreal min = Q_MIN_3(r, g, b); + const qreal delta = max - min; + const qreal delta2 = max + min; + const qreal lightness = qreal(0.5) * delta2; + color.ct.ahsl.lightness = qRound(lightness * USHRT_MAX); + if (qFuzzyIsNull(delta)) { + // achromatic case, hue is undefined + color.ct.ahsl.hue = 0; + color.ct.ahsl.saturation = 0; + } else { + // chromatic case + qreal hue = 0; + if (lightness < qreal(0.5)) + color.ct.ahsl.saturation = qRound((delta / delta2) * USHRT_MAX); + else + color.ct.ahsl.saturation = qRound((delta / (qreal(2.0) - delta2)) * USHRT_MAX); + if (qFuzzyCompare(r, max)) { + hue = ((g - b) /delta); + } else if (qFuzzyCompare(g, max)) { + hue = (2.0 + (b - r) / delta); + } else if (qFuzzyCompare(b, max)) { + hue = (4.0 + (r - g) / delta); + } else { + Q_ASSERT_X(false, "QColor::toHsv", "internal error"); + } + hue *= 60.0; + if (hue < 0.0) + hue += 360.0; + color.ct.ahsl.hue = qRound(hue * 100); + } + + return color; +} + +/*! Creates and returns a CMYK QColor based on this color. \sa fromCmyk(), convertTo(), isValid(), {QColor#The CMYK Color @@ -1466,6 +1815,8 @@ QColor QColor::convertTo(QColor::Spec colorSpec) const return toHsv(); case Cmyk: return toCmyk(); + case Hsl: + return toHsl(); case Invalid: break; } @@ -1627,6 +1978,70 @@ QColor QColor::fromHsvF(qreal h, qreal s, qreal v, qreal a) } /*! + Static convenience function that returns a QColor constructed from the HSV + color values, \a h (hue), \a s (saturation), \a l (lightness), and \a a + (alpha-channel, i.e. transparency). + + The value of \a s, \a l, and \a a must all be in the range 0-255; the value + of \a h must be in the range 0-359. + + \sa toHsl(), fromHslF(), isValid() +*/ +QColor QColor::fromHsl(int h, int s, int l, int a) +{ + if (((h < 0 || h >= 360) && h != -1) + || s < 0 || s > 255 + || l < 0 || l > 255 + || a < 0 || a > 255) { + qWarning("QColor::fromHsv: HSV parameters out of range"); + return QColor(); + } + + QColor color; + color.cspec = Hsl; + color.ct.ahsl.alpha = a * 0x101; + color.ct.ahsl.hue = h == -1 ? USHRT_MAX : (h % 360) * 100; + color.ct.ahsl.saturation = s * 0x101; + color.ct.ahsl.lightness = l * 0x101; + color.ct.ahsl.pad = 0; + return color; +} + +/*! + \overload + + Static convenience function that returns a QColor constructed from the HSV + color values, \a h (hue), \a s (saturation), \a l (lightness), and \a a + (alpha-channel, i.e. transparency). + + All the values must be in the range 0.0-1.0. + + \sa toHsl(), fromHsl(), isValid() +*/ +QColor QColor::fromHslF(qreal h, qreal s, qreal l, qreal a) +{ + if (((h < 0.0 || h > 1.0) && h != -1.0) + || (s < 0.0 || s > 1.0) + || (l < 0.0 || l > 1.0) + || (a < 0.0 || a > 1.0)) { + qWarning("QColor::fromHsvF: HSV parameters out of range"); + return QColor(); + } + + QColor color; + color.cspec = Hsl; + color.ct.ahsl.alpha = qRound(a * USHRT_MAX); + color.ct.ahsl.hue = (h == -1.0) ? USHRT_MAX : qRound(h * 36000); + if (color.ct.ahsl.hue == 36000) + color.ct.ahsl.hue = 0; + color.ct.ahsl.saturation = qRound(s * USHRT_MAX); + color.ct.ahsl.lightness = qRound(l * USHRT_MAX); + color.ct.ahsl.pad = 0; + return color; +} + + +/*! Sets the contents pointed to by \a c, \a m, \a y, \a k, and \a a, to the cyan, magenta, yellow, black, and alpha-channel (transparency) components of the color's CMYK value. @@ -1917,14 +2332,26 @@ QColor &QColor::operator=(Qt::GlobalColor color) */ bool QColor::operator==(const QColor &color) const { - return (cspec == color.cspec - && ct.argb.alpha == color.ct.argb.alpha - && ((cspec == QColor::Hsv - && ((ct.argb.red % 36000) == (color.ct.argb.red % 36000))) - || (ct.argb.red == color.ct.argb.red)) - && ct.argb.green == color.ct.argb.green - && ct.argb.blue == color.ct.argb.blue - && ct.argb.pad == color.ct.argb.pad); + if (cspec == Hsl && cspec == color.cspec) { + return (ct.argb.alpha == color.ct.argb.alpha + && ((((ct.ahsl.hue % 36000) == (color.ct.ahsl.hue % 36000))) + || (ct.ahsl.hue == color.ct.ahsl.hue)) + && (qAbs(ct.ahsl.saturation - color.ct.ahsl.saturation) < 50 + || ct.ahsl.lightness == 0 + || color.ct.ahsl.lightness == 0 + || ct.ahsl.lightness == USHRT_MAX + || color.ct.ahsl.lightness == USHRT_MAX) + && (qAbs(ct.ahsl.lightness - color.ct.ahsl.lightness)) < 50); + } else { + return (cspec == color.cspec + && ct.argb.alpha == color.ct.argb.alpha + && (((cspec == QColor::Hsv) + && ((ct.ahsv.hue % 36000) == (color.ct.ahsv.hue % 36000))) + || (ct.ahsv.hue == color.ct.ahsv.hue)) + && ct.argb.green == color.ct.argb.green + && ct.argb.blue == color.ct.argb.blue + && ct.argb.pad == color.ct.argb.pad); + } } /*! @@ -2028,6 +2455,8 @@ QDebug operator<<(QDebug dbg, const QColor &c) else if (c.spec() == QColor::Cmyk) dbg.nospace() << "QColor(ACMYK " << c.alphaF() << ", " << c.cyanF() << ", " << c.magentaF() << ", " << c.yellowF() << ", " << c.blackF()<< ')'; + else if (c.spec() == QColor::Hsl) + dbg.nospace() << "QColor(AHSL " << c.alphaF() << ", " << c.hslHueF() << ", " << c.hslSaturationF() << ", " << c.lightnessF() << ')'; return dbg.space(); #else diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h index 1a59029..a5e5210 100644 --- a/src/gui/painting/qcolor.h +++ b/src/gui/painting/qcolor.h @@ -67,7 +67,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QColor &); class Q_GUI_EXPORT QColor { public: - enum Spec { Invalid, Rgb, Hsv, Cmyk }; + enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl }; QColor(); QColor(Qt::GlobalColor color); @@ -122,10 +122,14 @@ public: int hue() const; // 0 <= hue < 360 int saturation() const; + int hsvHue() const; // 0 <= hue < 360 + int hsvSaturation() const; int value() const; qreal hueF() const; // 0.0 <= hueF < 360.0 qreal saturationF() const; + qreal hsvHueF() const; // 0.0 <= hueF < 360.0 + qreal hsvSaturationF() const; qreal valueF() const; void getHsv(int *h, int *s, int *v, int *a = 0) const; @@ -150,9 +154,24 @@ public: void getCmykF(qreal *c, qreal *m, qreal *y, qreal *k, qreal *a = 0); void setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a = 1.0); + int hslHue() const; // 0 <= hue < 360 + int hslSaturation() const; + int lightness() const; + + qreal hslHueF() const; // 0.0 <= hueF < 360.0 + qreal hslSaturationF() const; + qreal lightnessF() const; + + void getHsl(int *h, int *s, int *l, int *a = 0) const; + void setHsl(int h, int s, int l, int a = 255); + + void getHslF(qreal *h, qreal *s, qreal *l, qreal *a = 0) const; + void setHslF(qreal h, qreal s, qreal l, qreal a = 1.0); + QColor toRgb() const; QColor toHsv() const; QColor toCmyk() const; + QColor toHsl() const; QColor convertTo(Spec colorSpec) const; @@ -168,6 +187,9 @@ public: static QColor fromCmyk(int c, int m, int y, int k, int a = 255); static QColor fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a = 1.0); + static QColor fromHsl(int h, int s, int l, int a = 255); + static QColor fromHslF(qreal h, qreal s, qreal l, qreal a = 1.0); + QColor light(int f = 150) const; QColor lighter(int f = 150) const; QColor dark(int f = 200) const; @@ -234,6 +256,14 @@ private: ushort yellow; ushort black; } acmyk; + struct { + ushort alpha; + ushort hue; + ushort saturation; + ushort lightness; + ushort pad; + } ahsl; + ushort array[5]; } ct; friend class QColormap; |