diff --git a/modules/juce_core/unit_tests/juce_UnitTestCategories.h b/modules/juce_core/unit_tests/juce_UnitTestCategories.h index c0015a1758..9f6fa6ca9d 100644 --- a/modules/juce_core/unit_tests/juce_UnitTestCategories.h +++ b/modules/juce_core/unit_tests/juce_UnitTestCategories.h @@ -35,6 +35,7 @@ namespace UnitTestCategories static const String dsp { "DSP" }; static const String files { "Files" }; static const String function { "Function" }; + static const String graphics { "Graphics" }; static const String gui { "GUI" }; static const String json { "JSON" }; static const String maths { "Maths" }; diff --git a/modules/juce_graphics/colour/juce_Colour.cpp b/modules/juce_graphics/colour/juce_Colour.cpp index 89f083ad20..60db219787 100644 --- a/modules/juce_graphics/colour/juce_Colour.cpp +++ b/modules/juce_graphics/colour/juce_Colour.cpp @@ -21,58 +21,121 @@ namespace juce namespace ColourHelpers { - static uint8 floatToUInt8 (const float n) noexcept + static uint8 floatToUInt8 (float n) noexcept { - return n <= 0.0f ? 0 : (n >= 1.0f ? 255 : static_cast (n * 255.996f)); + return n <= 0.0f ? 0 : (n >= 1.0f ? 255 : (uint8) roundToInt (n * 255.0f)); } + static float getHue (Colour col) + { + auto r = (int) col.getRed(); + auto g = (int) col.getGreen(); + auto b = (int) col.getBlue(); + + auto hi = jmax (r, g, b); + auto lo = jmin (r, g, b); + + float hue = 0.0f; + + if (hi > 0) + { + auto invDiff = 1.0f / (hi - lo); + + auto red = (hi - r) * invDiff; + auto green = (hi - g) * invDiff; + auto blue = (hi - b) * invDiff; + + if (r == hi) hue = blue - green; + else if (g == hi) hue = 2.0f + red - blue; + else hue = 4.0f + green - red; + + hue *= 1.0f / 6.0f; + + if (hue < 0.0f) + hue += 1.0f; + } + + return hue; + } + + //============================================================================== + struct HSL + { + HSL (Colour col) noexcept + { + auto r = (int) col.getRed(); + auto g = (int) col.getGreen(); + auto b = (int) col.getBlue(); + + auto hi = jmax (r, g, b); + auto lo = jmin (r, g, b); + + if (hi > 0) + { + lightness = ((hi + lo) / 2.0f) / 255.0f; + + if (lightness > 0.0f) + hue = getHue (col); + + saturation = (hi - lo) / (1.0f - std::abs ((2.0f * lightness) - 1.0f)); + } + } + + Colour toColour (Colour original) const noexcept + { + return Colour::fromHSL (hue, saturation, lightness, original.getAlpha()); + } + + static PixelARGB toRGB (float h, float s, float l, uint8 alpha) noexcept + { + auto v = l < 0.5f ? l * (1.0f + s) : l + s - (l * s); + + if (approximatelyEqual (v, 0.0f)) + return PixelARGB (alpha, 0, 0, 0); + + auto min = (2.0f * l) - v; + auto sv = (v - min) / v; + + h = jlimit (0.0f, 360.0f, h * 360.0f) / 60.0f; + auto f = h - std::floor (h); + auto vsf = v * sv * f; + auto mid1 = min + vsf; + auto mid2 = v - vsf; + + if (h < 1.0f) return PixelARGB (alpha, floatToUInt8 (v), floatToUInt8 (mid1), floatToUInt8 (min)); + else if (h < 2.0f) return PixelARGB (alpha, floatToUInt8 (mid2), floatToUInt8 (v), floatToUInt8 (min)); + else if (h < 3.0f) return PixelARGB (alpha, floatToUInt8 (min), floatToUInt8 (v), floatToUInt8 (mid1)); + else if (h < 4.0f) return PixelARGB (alpha, floatToUInt8 (min), floatToUInt8 (mid2), floatToUInt8 (v)); + else if (h < 5.0f) return PixelARGB (alpha, floatToUInt8 (mid1), floatToUInt8 (min), floatToUInt8 (v)); + else if (h < 6.0f) return PixelARGB (alpha, floatToUInt8 (v), floatToUInt8 (min), floatToUInt8 (mid2)); + + return PixelARGB (alpha, 0, 0, 0); + } + + float hue = 0.0f, saturation = 0.0f, lightness = 0.0f; + }; + //============================================================================== struct HSB { HSB (Colour col) noexcept { - const int r = col.getRed(); - const int g = col.getGreen(); - const int b = col.getBlue(); + auto r = (int) col.getRed(); + auto g = (int) col.getGreen(); + auto b = (int) col.getBlue(); - const int hi = jmax (r, g, b); - const int lo = jmin (r, g, b); + auto hi = jmax (r, g, b); + auto lo = jmin (r, g, b); - if (hi != 0) + if (hi > 0) { saturation = (hi - lo) / (float) hi; - if (saturation > 0) - { - const float invDiff = 1.0f / (hi - lo); + if (saturation > 0.0f) + hue = getHue (col); - const float red = (hi - r) * invDiff; - const float green = (hi - g) * invDiff; - const float blue = (hi - b) * invDiff; - - if (r == hi) - hue = blue - green; - else if (g == hi) - hue = 2.0f + red - blue; - else - hue = 4.0f + green - red; - - hue *= 1.0f / 6.0f; - - if (hue < 0) - ++hue; - } - else - { - hue = 0; - } + brightness = hi / 255.0f; } - else - { - saturation = hue = 0; - } - - brightness = hi / 255.0f; } Colour toColour (Colour original) const noexcept @@ -80,18 +143,18 @@ namespace ColourHelpers return Colour (hue, saturation, brightness, original.getAlpha()); } - static PixelARGB toRGB (float h, float s, float v, const uint8 alpha) noexcept + static PixelARGB toRGB (float h, float s, float v, uint8 alpha) noexcept { v = jlimit (0.0f, 255.0f, v * 255.0f); - const uint8 intV = (uint8) roundToInt (v); + auto intV = (uint8) roundToInt (v); if (s <= 0) return PixelARGB (alpha, intV, intV, intV); s = jmin (1.0f, s); - h = (h - std::floor (h)) * 6.0f + 0.00001f; // need a small adjustment to compensate for rounding errors - const float f = h - std::floor (h); - const uint8 x = (uint8) roundToInt (v * (1.0f - s)); + h = jlimit (0.0f, 360.0f, h * 360.0f) / 60.0f; + auto f = h - std::floor (h); + auto x = (uint8) roundToInt (v * (1.0f - s)); if (h < 1.0f) return PixelARGB (alpha, intV, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))), x); if (h < 2.0f) return PixelARGB (alpha, (uint8) roundToInt (v * (1.0f - s * f)), intV, x); @@ -101,7 +164,7 @@ namespace ColourHelpers return PixelARGB (alpha, intV, x, (uint8) roundToInt (v * (1.0f - s * f))); } - float hue, saturation, brightness; + float hue = 0.0f, saturation = 0.0f, brightness = 0.0f; }; //============================================================================== @@ -109,9 +172,9 @@ namespace ColourHelpers { YIQ (Colour c) noexcept { - const float r = c.getFloatRed(); - const float g = c.getFloatGreen(); - const float b = c.getFloatBlue(); + auto r = c.getFloatRed(); + auto g = c.getFloatGreen(); + auto b = c.getFloatBlue(); y = 0.2999f * r + 0.5870f * g + 0.1140f * b; i = 0.5957f * r - 0.2744f * g - 0.3212f * b; @@ -127,7 +190,7 @@ namespace ColourHelpers alpha); } - float y, i, q, alpha; + float y = 0.0f, i = 0.0f, q = 0.0f, alpha = 0.0f; }; } @@ -136,7 +199,7 @@ bool Colour::operator== (const Colour& other) const noexcept { return argb.ge bool Colour::operator!= (const Colour& other) const noexcept { return argb.getNativeARGB() != other.argb.getNativeARGB(); } //============================================================================== -Colour::Colour (const uint32 col) noexcept +Colour::Colour (uint32 col) noexcept : argb (static_cast ((col >> 24) & 0xff), static_cast ((col >> 16) & 0xff), static_cast ((col >> 8) & 0xff), @@ -144,49 +207,57 @@ Colour::Colour (const uint32 col) noexcept { } -Colour::Colour (const uint8 red, const uint8 green, const uint8 blue) noexcept +Colour::Colour (uint8 red, uint8 green, uint8 blue) noexcept { argb.setARGB (0xff, red, green, blue); } -Colour Colour::fromRGB (const uint8 red, const uint8 green, const uint8 blue) noexcept +Colour Colour::fromRGB (uint8 red, uint8 green, uint8 blue) noexcept { return Colour (red, green, blue); } -Colour::Colour (const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) noexcept +Colour::Colour (uint8 red, uint8 green, uint8 blue, uint8 alpha) noexcept { argb.setARGB (alpha, red, green, blue); } -Colour Colour::fromRGBA (const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) noexcept +Colour Colour::fromRGBA (uint8 red, uint8 green, uint8 blue, uint8 alpha) noexcept { return Colour (red, green, blue, alpha); } -Colour::Colour (const uint8 red, const uint8 green, const uint8 blue, const float alpha) noexcept +Colour::Colour (uint8 red, uint8 green, uint8 blue, float alpha) noexcept { argb.setARGB (ColourHelpers::floatToUInt8 (alpha), red, green, blue); } -Colour Colour::fromFloatRGBA (const float red, const float green, const float blue, const float alpha) noexcept +Colour Colour::fromFloatRGBA (float red, float green, float blue, float alpha) noexcept { return Colour (ColourHelpers::floatToUInt8 (red), ColourHelpers::floatToUInt8 (green), ColourHelpers::floatToUInt8 (blue), alpha); } -Colour::Colour (const float hue, const float saturation, const float brightness, const float alpha) noexcept +Colour::Colour (float hue, float saturation, float brightness, float alpha) noexcept : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, ColourHelpers::floatToUInt8 (alpha))) { } -Colour Colour::fromHSV (const float hue, const float saturation, const float brightness, const float alpha) noexcept +Colour Colour::fromHSV (float hue, float saturation, float brightness, float alpha) noexcept { return Colour (hue, saturation, brightness, alpha); } -Colour::Colour (const float hue, const float saturation, const float brightness, const uint8 alpha) noexcept +Colour Colour::fromHSL (float hue, float saturation, float lightness, float alpha) noexcept +{ + Colour hslColour; + hslColour.argb = ColourHelpers::HSL::toRGB (hue, saturation, lightness, ColourHelpers::floatToUInt8 (alpha)); + + return hslColour; +} + +Colour::Colour (float hue, float saturation, float brightness, uint8 alpha) noexcept : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, alpha)) { } @@ -258,18 +329,18 @@ Colour Colour::withMultipliedAlpha (const float alphaMultiplier) const noexcept //============================================================================== Colour Colour::overlaidWith (Colour src) const noexcept { - const int destAlpha = getAlpha(); + auto destAlpha = getAlpha(); if (destAlpha <= 0) return src; - const int invA = 0xff - (int) src.getAlpha(); - const int resA = 0xff - (((0xff - destAlpha) * invA) >> 8); + auto invA = 0xff - (int) src.getAlpha(); + auto resA = 0xff - (((0xff - destAlpha) * invA) >> 8); if (resA <= 0) return *this; - const int da = (invA * destAlpha) / resA; + auto da = (invA * destAlpha) / resA; return Colour ((uint8) (src.getRed() + ((((int) getRed() - src.getRed()) * da) >> 8)), (uint8) (src.getGreen() + ((((int) getGreen() - src.getGreen()) * da) >> 8)), @@ -286,7 +357,7 @@ Colour Colour::interpolatedWith (Colour other, float proportionOfOther) const no return other; PixelARGB c1 (getPixelARGB()); - const PixelARGB c2 (other.getPixelARGB()); + PixelARGB c2 (other.getPixelARGB()); c1.tween (c2, (uint32) roundToInt (proportionOfOther * 255.0f)); c1.unpremultiply(); @@ -302,20 +373,32 @@ float Colour::getFloatAlpha() const noexcept { return getAlpha() / 255.0f; } //============================================================================== void Colour::getHSB (float& h, float& s, float& v) const noexcept { - const ColourHelpers::HSB hsb (*this); + ColourHelpers::HSB hsb (*this); h = hsb.hue; s = hsb.saturation; v = hsb.brightness; } +void Colour::getHSL (float& h, float& s, float& l) const noexcept +{ + ColourHelpers::HSL hsl (*this); + h = hsl.hue; + s = hsl.saturation; + l = hsl.lightness; +} + float Colour::getHue() const noexcept { return ColourHelpers::HSB (*this).hue; } float Colour::getSaturation() const noexcept { return ColourHelpers::HSB (*this).saturation; } float Colour::getBrightness() const noexcept { return ColourHelpers::HSB (*this).brightness; } +float Colour::getLightness() const noexcept { return ColourHelpers::HSL (*this).lightness; } + Colour Colour::withHue (float h) const noexcept { ColourHelpers::HSB hsb (*this); hsb.hue = h; return hsb.toColour (*this); } Colour Colour::withSaturation (float s) const noexcept { ColourHelpers::HSB hsb (*this); hsb.saturation = s; return hsb.toColour (*this); } Colour Colour::withBrightness (float v) const noexcept { ColourHelpers::HSB hsb (*this); hsb.brightness = v; return hsb.toColour (*this); } +Colour Colour::withLightness (float l) const noexcept { ColourHelpers::HSL hsl (*this); hsl.lightness = l; return hsl.toColour (*this); } + float Colour::getPerceivedBrightness() const noexcept { return std::sqrt (0.241f * square (getFloatRed()) @@ -345,6 +428,13 @@ Colour Colour::withMultipliedBrightness (const float amount) const noexcept return hsb.toColour (*this); } +Colour Colour::withMultipliedLightness (const float amount) const noexcept +{ + ColourHelpers::HSL hsl (*this); + hsl.lightness = jmin (1.0f, hsl.lightness * amount); + return hsl.toColour (*this); +} + //============================================================================== Colour Colour::brighter (float amount) const noexcept { @@ -369,7 +459,7 @@ Colour Colour::darker (float amount) const noexcept //============================================================================== Colour Colour::greyLevel (const float brightness) noexcept { - const uint8 level = ColourHelpers::floatToUInt8 (brightness); + auto level = ColourHelpers::floatToUInt8 (brightness); return Colour (level, level, level); } @@ -383,14 +473,14 @@ Colour Colour::contrasting (const float amount) const noexcept Colour Colour::contrasting (Colour target, float minContrast) const noexcept { - const ColourHelpers::YIQ bg (*this); + ColourHelpers::YIQ bg (*this); ColourHelpers::YIQ fg (target); if (std::abs (bg.y - fg.y) >= minContrast) return target; - const float y1 = jmax (0.0f, bg.y - minContrast); - const float y2 = jmin (1.0f, bg.y + minContrast); + auto y1 = jmax (0.0f, bg.y - minContrast); + auto y2 = jmin (1.0f, bg.y + minContrast); fg.y = (std::abs (y1 - bg.y) > std::abs (y2 - bg.y)) ? y1 : y2; return fg.toColour(); @@ -399,16 +489,15 @@ Colour Colour::contrasting (Colour target, float minContrast) const noexcept Colour Colour::contrasting (Colour colour1, Colour colour2) noexcept { - const float b1 = colour1.getPerceivedBrightness(); - const float b2 = colour2.getPerceivedBrightness(); - float best = 0.0f; - float bestDist = 0.0f; + auto b1 = colour1.getPerceivedBrightness(); + auto b2 = colour2.getPerceivedBrightness(); + float best = 0.0f, bestDist = 0.0f; for (float i = 0.0f; i < 1.0f; i += 0.02f) { - const float d1 = std::abs (i - b1); - const float d2 = std::abs (i - b2); - const float dist = jmin (d1, d2, 1.0f - d1, 1.0f - d2); + auto d1 = std::abs (i - b1); + auto d2 = std::abs (i - b2); + auto dist = jmin (d1, d2, 1.0f - d1, 1.0f - d2); if (dist > bestDist) { @@ -439,4 +528,188 @@ String Colour::toDisplayString (const bool includeAlphaValue) const .toUpperCase(); } + +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +class ColourTests : public UnitTest +{ +public: + ColourTests() + : UnitTest ("Colour", UnitTestCategories::graphics) + {} + + void runTest() override + { + beginTest ("Constructors"); + { + Colour c1; + expectEquals (c1.getRed(), (uint8) 0); + expectEquals (c1.getGreen(), (uint8) 0); + expectEquals (c1.getBlue(), (uint8) 0); + expectEquals (c1.getAlpha(), (uint8) 0); + expectEquals (c1.getFloatAlpha(), 0.0f); + + Colour c2 ((uint32) 0); + expectEquals (c2.getRed(), (uint8) 0); + expectEquals (c2.getGreen(), (uint8) 0); + expectEquals (c2.getBlue(), (uint8) 0); + expectEquals (c2.getAlpha(), (uint8) 0); + expectEquals (c2.getFloatAlpha(), 0.0f); + + Colour c3 ((uint32) 0xffffffff); + expectEquals (c3.getRed(), (uint8) 255); + expectEquals (c3.getGreen(), (uint8) 255); + expectEquals (c3.getBlue(), (uint8) 255); + expectEquals (c3.getAlpha(), (uint8) 255); + expectEquals (c3.getFloatAlpha(), 1.0f); + + Colour c4 (0, 0, 0); + expectEquals (c4.getRed(), (uint8) 0); + expectEquals (c4.getGreen(), (uint8) 0); + expectEquals (c4.getBlue(), (uint8) 0); + expectEquals (c4.getAlpha(), (uint8) 255); + expectEquals (c4.getFloatAlpha(), 1.0f); + + Colour c5 (255, 255, 255); + expectEquals (c5.getRed(), (uint8) 255); + expectEquals (c5.getGreen(), (uint8) 255); + expectEquals (c5.getBlue(), (uint8) 255); + expectEquals (c5.getAlpha(), (uint8) 255); + expectEquals (c5.getFloatAlpha(), 1.0f); + + Colour c6 ((uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0); + expectEquals (c6.getRed(), (uint8) 0); + expectEquals (c6.getGreen(), (uint8) 0); + expectEquals (c6.getBlue(), (uint8) 0); + expectEquals (c6.getAlpha(), (uint8) 0); + expectEquals (c6.getFloatAlpha(), 0.0f); + + Colour c7 ((uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255); + expectEquals (c7.getRed(), (uint8) 255); + expectEquals (c7.getGreen(), (uint8) 255); + expectEquals (c7.getBlue(), (uint8) 255); + expectEquals (c7.getAlpha(), (uint8) 255); + expectEquals (c7.getFloatAlpha(), 1.0f); + + Colour c8 ((uint8) 0, (uint8) 0, (uint8) 0, 0.0f); + expectEquals (c8.getRed(), (uint8) 0); + expectEquals (c8.getGreen(), (uint8) 0); + expectEquals (c8.getBlue(), (uint8) 0); + expectEquals (c8.getAlpha(), (uint8) 0); + expectEquals (c8.getFloatAlpha(), 0.0f); + + Colour c9 ((uint8) 255, (uint8) 255, (uint8) 255, 1.0f); + expectEquals (c9.getRed(), (uint8) 255); + expectEquals (c9.getGreen(), (uint8) 255); + expectEquals (c9.getBlue(), (uint8) 255); + expectEquals (c9.getAlpha(), (uint8) 255); + expectEquals (c9.getFloatAlpha(), 1.0f); + } + + beginTest ("HSV"); + { + auto testHSV = [this] (int hueDegrees, int saturationPercentage, int brightnessPercentage, + uint8 expectedRed, uint8 expectedGreen, uint8 expectedBlue) + { + auto testColour = Colour::fromHSV (hueDegrees / 360.0f, + saturationPercentage / 100.0f, + brightnessPercentage / 100.0f, + 1.0f); + + expectEquals (testColour.getRed(), expectedRed); + expectEquals (testColour.getGreen(), expectedGreen); + expectEquals (testColour.getBlue(), expectedBlue); + }; + + // black + testHSV (0, 0, 0, 0, 0, 0); + // white + testHSV (0, 0, 100, 255, 255, 255); + // red + testHSV (0, 100, 100, 255, 0, 0); + // lime + testHSV (120, 100, 100, 0, 255, 0); + // blue + testHSV (240, 100, 100, 0, 0, 255); + // yellow + testHSV (60, 100, 100, 255, 255, 0); + // cyan + testHSV (180, 100, 100, 0, 255, 255); + // magenta + testHSV (300, 100, 100, 255, 0, 255); + // silver + testHSV (0, 0, 75, 191, 191, 191); + // grey + testHSV (0, 0, 50, 128, 128, 128); + // maroon + testHSV (0, 100, 50, 128, 0, 0); + // olive + testHSV (60, 100, 50, 128, 128, 0); + // green + testHSV (120, 100, 50, 0, 128, 0); + // purple + testHSV (300, 100, 50, 128, 0, 128); + // teal + testHSV (180, 100, 50, 0, 128, 128); + // navy + testHSV (240, 100, 50, 0, 0, 128); + } + + beginTest ("HSL"); + { + auto testHSL = [this] (int hueDegrees, int saturationPercentage, int lightnessPercentage, + uint8 expectedRed, uint8 expectedGreen, uint8 expectedBlue) + { + auto testColour = Colour::fromHSL (hueDegrees / 360.0f, + saturationPercentage / 100.0f, + lightnessPercentage / 100.0f, + 1.0f); + + expectEquals (testColour.getRed(), expectedRed); + expectEquals (testColour.getGreen(), expectedGreen); + expectEquals (testColour.getBlue(), expectedBlue); + }; + + // black + testHSL (0, 0, 0, 0, 0, 0); + // white + testHSL (0, 0, 100, 255, 255, 255); + // red + testHSL (0, 100, 50, 255, 0, 0); + // lime + testHSL (120, 100, 50, 0, 255, 0); + // blue + testHSL (240, 100, 50, 0, 0, 255); + // yellow + testHSL (60, 100, 50, 255, 255, 0); + // cyan + testHSL (180, 100, 50, 0, 255, 255); + // magenta + testHSL (300, 100, 50, 255, 0, 255); + // silver + testHSL (0, 0, 75, 191, 191, 191); + // grey + testHSL (0, 0, 50, 128, 128, 128); + // maroon + testHSL (0, 100, 25, 128, 0, 0); + // olive + testHSL (60, 100, 25, 128, 128, 0); + // green + testHSL (120, 100, 25, 0, 128, 0); + // purple + testHSL (300, 100, 25, 128, 0, 128); + // teal + testHSL (180, 100, 25, 0, 128, 128); + // navy + testHSL (240, 100, 25, 0, 0, 128); + } + } +}; + +static ColourTests colourTests; + +#endif + } // namespace juce diff --git a/modules/juce_graphics/colour/juce_Colour.h b/modules/juce_graphics/colour/juce_Colour.h index aa3490bf15..31694f9802 100644 --- a/modules/juce_graphics/colour/juce_Colour.h +++ b/modules/juce_graphics/colour/juce_Colour.h @@ -110,6 +110,26 @@ public: float brightness, float alpha) noexcept; + /** Creates a colour using floating point hue, saturation, brightness and alpha values. + + All values must be between 0.0 and 1.0. + Numbers outside the valid range will be clipped. + */ + static Colour fromHSV (float hue, + float saturation, + float brightness, + float alpha) noexcept; + + /** Creates a colour using floating point hue, saturation, lightness and alpha values. + + All values must be between 0.0 and 1.0. + Numbers outside the valid range will be clipped. + */ + static Colour fromHSL (float hue, + float saturation, + float lightness, + float alpha) noexcept; + /** Creates a colour using a PixelARGB object. This function assumes that the argb pixel is not premultiplied. */ @@ -123,16 +143,6 @@ public: */ Colour (PixelAlpha alpha) noexcept; - /** Creates a colour using floating point hue, saturation, brightness and alpha values. - - All values must be between 0.0 and 1.0. - Numbers outside the valid range will be clipped. - */ - static Colour fromHSV (float hue, - float saturation, - float brightness, - float alpha) noexcept; - /** Destructor. */ ~Colour() = default; @@ -250,6 +260,11 @@ public: */ float getBrightness() const noexcept; + /** Returns the colour's lightness component. + The value returned is in the range 0.0 to 1.0 + */ + float getLightness() const noexcept; + /** Returns a skewed brightness value, adjusted to better reflect the way the human eye responds to different colour channels. This makes it better than getBrightness() for comparing differences in brightness. @@ -263,6 +278,13 @@ public: float& saturation, float& brightness) const noexcept; + /** Returns the colour's hue, saturation and lightness components all at once. + The values returned are in the range 0.0 to 1.0 + */ + void getHSL (float& hue, + float& saturation, + float& lightness) const noexcept; + //============================================================================== /** Returns a copy of this colour with a different hue. */ Colour withHue (float newHue) const noexcept; @@ -275,6 +297,11 @@ public: */ Colour withBrightness (float newBrightness) const noexcept; + /** Returns a copy of this colour with a different lightness. + @see lighter, darker, withMultipliedLightness + */ + Colour withLightness (float newLightness) const noexcept; + /** Returns a copy of this colour with its hue rotated. The new colour's hue is ((this->getHue() + amountToRotate) % 1.0) @see brighter, darker, withMultipliedBrightness @@ -293,6 +320,12 @@ public: */ Colour withMultipliedBrightness (float amount) const noexcept; + /** Returns a copy of this colour with its lightness multiplied by the given value. + The new colour's lightness is (this->lightness() * multiplier) + (the result is clipped to legal limits). + */ + Colour withMultipliedLightness (float amount) const noexcept; + //============================================================================== /** Returns a brighter version of this colour. @param amountBrighter how much brighter to make it - a value from 0 to 1.0 where 0 is diff --git a/modules/juce_gui_basics/drawables/juce_SVGParser.cpp b/modules/juce_gui_basics/drawables/juce_SVGParser.cpp index 31bc56e5cb..677a3f6aa2 100644 --- a/modules/juce_gui_basics/drawables/juce_SVGParser.cpp +++ b/modules/juce_gui_basics/drawables/juce_SVGParser.cpp @@ -1573,10 +1573,10 @@ private: }(); if (text.startsWith ("hsl")) - return Colour ((float) (tokens[0].getDoubleValue() / 360.0), - (float) (tokens[1].getDoubleValue() / 100.0), - (float) (tokens[2].getDoubleValue() / 100.0), - alpha); + return Colour::fromHSL ((float) (tokens[0].getDoubleValue() / 360.0), + (float) (tokens[1].getDoubleValue() / 100.0), + (float) (tokens[2].getDoubleValue() / 100.0), + alpha); if (tokens[0].containsChar ('%')) return Colour ((uint8) roundToInt (2.55 * tokens[0].getDoubleValue()),