From 68f7ed4ecca81e530fd22213414ca14c688e0c92 Mon Sep 17 00:00:00 2001 From: Anthony Nicholls Date: Mon, 13 Oct 2025 13:16:32 +0100 Subject: [PATCH] Colour: Prevent an integer alpha value being processed as a float --- modules/juce_graphics/colour/juce_Colour.cpp | 77 ++++++++++++++++---- modules/juce_graphics/colour/juce_Colour.h | 22 ++++++ 2 files changed, 83 insertions(+), 16 deletions(-) diff --git a/modules/juce_graphics/colour/juce_Colour.cpp b/modules/juce_graphics/colour/juce_Colour.cpp index 67bbb336c4..bbcceb8dbf 100644 --- a/modules/juce_graphics/colour/juce_Colour.cpp +++ b/modules/juce_graphics/colour/juce_Colour.cpp @@ -271,10 +271,20 @@ Colour Colour::fromHSV (float hue, float saturation, float brightness, float alp return Colour (hue, saturation, brightness, alpha); } +Colour Colour::fromHSV (float hue, float saturation, float brightness, uint8 alpha) noexcept +{ + return Colour (hue, saturation, brightness, alpha); +} + Colour Colour::fromHSL (float hue, float saturation, float lightness, float alpha) noexcept +{ + return fromHSL (hue, saturation, lightness, ColourHelpers::floatToUInt8 (alpha)); +} + +Colour Colour::fromHSL (float hue, float saturation, float lightness, uint8 alpha) noexcept { Colour hslColour; - hslColour.argb = ColourHelpers::HSL::toRGB (hue, saturation, lightness, ColourHelpers::floatToUInt8 (alpha)); + hslColour.argb = ColourHelpers::HSL::toRGB (hue, saturation, lightness, alpha); return hslColour; } @@ -582,117 +592,150 @@ public: { auto testColour = [this] (Colour colour, uint8 expectedRed, uint8 expectedGreen, uint8 expectedBlue, - uint8 expectedAlpha = 255, float expectedFloatAlpha = 1.0f) + uint8 expectedAlpha = 255) { - expectEquals (colour.getRed(), expectedRed); - expectEquals (colour.getGreen(), expectedGreen); - expectEquals (colour.getBlue(), expectedBlue); - expectEquals (colour.getAlpha(), expectedAlpha); - expectEquals (colour.getFloatAlpha(), expectedFloatAlpha); + expectEquals (colour.getRed(), expectedRed); + expectEquals (colour.getGreen(), expectedGreen); + expectEquals (colour.getBlue(), expectedBlue); + expectEquals (colour.getAlpha(), expectedAlpha); }; beginTest ("Constructors"); { Colour c1; - testColour (c1, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0, 0.0f); + testColour (c1, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0); Colour c2 ((uint32) 0); - testColour (c2, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0, 0.0f); + testColour (c2, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0); Colour c3 ((uint32) 0xffffffff); - testColour (c3, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255, 1.0f); + testColour (c3, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255); Colour c4 (0, 0, 0); - testColour (c4, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 255, 1.0f); + testColour (c4, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 255); Colour c5 (255, 255, 255); - testColour (c5, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255, 1.0f); + testColour (c5, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255); Colour c6 ((uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0); - testColour (c6, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0, 0.0f); + testColour (c6, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0); Colour c7 ((uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255); - testColour (c7, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255, 1.0f); + testColour (c7, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255); Colour c8 ((uint8) 0, (uint8) 0, (uint8) 0, 0.0f); - testColour (c8, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0, 0.0f); + testColour (c8, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0); Colour c9 ((uint8) 255, (uint8) 255, (uint8) 255, 1.0f); - testColour (c9, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255, 1.0f); + testColour (c9, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255); } beginTest ("HSV"); { // black testColour (Colour::fromHSV (0.0f, 0.0f, 0.0f, 1.0f), 0, 0, 0); + testColour (Colour::fromHSV (0.0f, 0.0f, 0.0f, 0.5f), 0, 0, 0, 128); // white testColour (Colour::fromHSV (0.0f, 0.0f, 1.0f, 1.0f), 255, 255, 255); + testColour (Colour::fromHSV (0.0f, 0.0f, 1.0f, 0.5f), 255, 255, 255, 128); // red testColour (Colour::fromHSV (0.0f, 1.0f, 1.0f, 1.0f), 255, 0, 0); + testColour (Colour::fromHSV (0.0f, 1.0f, 1.0f, 0.5f), 255, 0, 0, 128); testColour (Colour::fromHSV (1.0f, 1.0f, 1.0f, 1.0f), 255, 0, 0); + testColour (Colour::fromHSV (1.0f, 1.0f, 1.0f, 0.5f), 255, 0, 0, 128); // lime testColour (Colour::fromHSV (120 / 360.0f, 1.0f, 1.0f, 1.0f), 0, 255, 0); + testColour (Colour::fromHSV (120 / 360.0f, 1.0f, 1.0f, 0.5f), 0, 255, 0, 128); // blue testColour (Colour::fromHSV (240 / 360.0f, 1.0f, 1.0f, 1.0f), 0, 0, 255); + testColour (Colour::fromHSV (240 / 360.0f, 1.0f, 1.0f, 0.5f), 0, 0, 255, 128); // yellow testColour (Colour::fromHSV (60 / 360.0f, 1.0f, 1.0f, 1.0f), 255, 255, 0); + testColour (Colour::fromHSV (60 / 360.0f, 1.0f, 1.0f, 0.5f), 255, 255, 0, 128); // cyan testColour (Colour::fromHSV (180 / 360.0f, 1.0f, 1.0f, 1.0f), 0, 255, 255); + testColour (Colour::fromHSV (180 / 360.0f, 1.0f, 1.0f, 0.5f), 0, 255, 255, 128); // magenta testColour (Colour::fromHSV (300 / 360.0f, 1.0f, 1.0f, 1.0f), 255, 0, 255); + testColour (Colour::fromHSV (300 / 360.0f, 1.0f, 1.0f, 0.5f), 255, 0, 255, 128); // silver testColour (Colour::fromHSV (0.0f, 0.0f, 0.75f, 1.0f), 191, 191, 191); + testColour (Colour::fromHSV (0.0f, 0.0f, 0.75f, 0.5f), 191, 191, 191, 128); // grey testColour (Colour::fromHSV (0.0f, 0.0f, 0.5f, 1.0f), 128, 128, 128); + testColour (Colour::fromHSV (0.0f, 0.0f, 0.5f, 0.5f), 128, 128, 128, 128); // maroon testColour (Colour::fromHSV (0.0f, 1.0f, 0.5f, 1.0f), 128, 0, 0); + testColour (Colour::fromHSV (0.0f, 1.0f, 0.5f, 0.5f), 128, 0, 0, 128); // olive testColour (Colour::fromHSV (60 / 360.0f, 1.0f, 0.5f, 1.0f), 128, 128, 0); + testColour (Colour::fromHSV (60 / 360.0f, 1.0f, 0.5f, 0.5f), 128, 128, 0, 128); // green testColour (Colour::fromHSV (120 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 128, 0); + testColour (Colour::fromHSV (120 / 360.0f, 1.0f, 0.5f, 0.5f), 0, 128, 0, 128); // purple testColour (Colour::fromHSV (300 / 360.0f, 1.0f, 0.5f, 1.0f), 128, 0, 128); + testColour (Colour::fromHSV (300 / 360.0f, 1.0f, 0.5f, 0.5f), 128, 0, 128, 128); // teal testColour (Colour::fromHSV (180 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 128, 128); + testColour (Colour::fromHSV (180 / 360.0f, 1.0f, 0.5f, 0.5f), 0, 128, 128, 128); // navy testColour (Colour::fromHSV (240 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 0, 128); + testColour (Colour::fromHSV (240 / 360.0f, 1.0f, 0.5f, 0.5f), 0, 0, 128, 128); } beginTest ("HSL"); { // black testColour (Colour::fromHSL (0.0f, 0.0f, 0.0f, 1.0f), 0, 0, 0); + testColour (Colour::fromHSL (0.0f, 0.0f, 0.0f, 0.5f), 0, 0, 0, 128); // white testColour (Colour::fromHSL (0.0f, 0.0f, 1.0f, 1.0f), 255, 255, 255); + testColour (Colour::fromHSL (0.0f, 0.0f, 1.0f, 0.5f), 255, 255, 255, 128); // red testColour (Colour::fromHSL (0.0f, 1.0f, 0.5f, 1.0f), 255, 0, 0); + testColour (Colour::fromHSL (0.0f, 1.0f, 0.5f, 0.5f), 255, 0, 0, 128); testColour (Colour::fromHSL (1.0f, 1.0f, 0.5f, 1.0f), 255, 0, 0); + testColour (Colour::fromHSL (1.0f, 1.0f, 0.5f, 0.5f), 255, 0, 0, 128); // lime testColour (Colour::fromHSL (120 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 255, 0); + testColour (Colour::fromHSL (120 / 360.0f, 1.0f, 0.5f, 0.5f), 0, 255, 0, 128); // blue testColour (Colour::fromHSL (240 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 0, 255); + testColour (Colour::fromHSL (240 / 360.0f, 1.0f, 0.5f, 0.5f), 0, 0, 255, 128); // yellow testColour (Colour::fromHSL (60 / 360.0f, 1.0f, 0.5f, 1.0f), 255, 255, 0); + testColour (Colour::fromHSL (60 / 360.0f, 1.0f, 0.5f, 0.5f), 255, 255, 0, 128); // cyan testColour (Colour::fromHSL (180 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 255, 255); + testColour (Colour::fromHSL (180 / 360.0f, 1.0f, 0.5f, 0.5f), 0, 255, 255, 128); // magenta testColour (Colour::fromHSL (300 / 360.0f, 1.0f, 0.5f, 1.0f), 255, 0, 255); + testColour (Colour::fromHSL (300 / 360.0f, 1.0f, 0.5f, 0.5f), 255, 0, 255, 128); // silver testColour (Colour::fromHSL (0.0f, 0.0f, 0.75f, 1.0f), 191, 191, 191); + testColour (Colour::fromHSL (0.0f, 0.0f, 0.75f, 0.5f), 191, 191, 191, 128); // grey testColour (Colour::fromHSL (0.0f, 0.0f, 0.5f, 1.0f), 128, 128, 128); + testColour (Colour::fromHSL (0.0f, 0.0f, 0.5f, 0.5f), 128, 128, 128, 128); // maroon testColour (Colour::fromHSL (0.0f, 1.0f, 0.25f, 1.0f), 128, 0, 0); + testColour (Colour::fromHSL (0.0f, 1.0f, 0.25f, 0.5f), 128, 0, 0, 128); // olive testColour (Colour::fromHSL (60 / 360.0f, 1.0f, 0.25f, 1.0f), 128, 128, 0); + testColour (Colour::fromHSL (60 / 360.0f, 1.0f, 0.25f, 0.5f), 128, 128, 0, 128); // green testColour (Colour::fromHSL (120 / 360.0f, 1.0f, 0.25f, 1.0f), 0, 128, 0); + testColour (Colour::fromHSL (120 / 360.0f, 1.0f, 0.25f, 0.5f), 0, 128, 0, 128); // purple testColour (Colour::fromHSL (300 / 360.0f, 1.0f, 0.25f, 1.0f), 128, 0, 128); + testColour (Colour::fromHSL (300 / 360.0f, 1.0f, 0.25f, 0.5f), 128, 0, 128, 128); // teal testColour (Colour::fromHSL (180 / 360.0f, 1.0f, 0.25f, 1.0f), 0, 128, 128); + testColour (Colour::fromHSL (180 / 360.0f, 1.0f, 0.25f, 0.5f), 0, 128, 128, 128); // navy testColour (Colour::fromHSL (240 / 360.0f, 1.0f, 0.25f, 1.0f), 0, 0, 128); + testColour (Colour::fromHSL (240 / 360.0f, 1.0f, 0.25f, 0.5f), 0, 0, 128, 128); } beginTest ("Modifiers"); @@ -715,6 +758,8 @@ public: testColour (red.withMultipliedLightness (2.0f), 255, 255, 255); testColour (red.withMultipliedLightness (1.0f), 255, 0, 0); testColour (red.withLightness (red.getLightness()), 255, 0, 0); + testColour (red.withAlpha ((uint8) 128), 255, 0, 0, 128); + testColour (red.withAlpha (0.5f), 255, 0, 0, 128); } } }; diff --git a/modules/juce_graphics/colour/juce_Colour.h b/modules/juce_graphics/colour/juce_Colour.h index c274bd6f3e..30250d439d 100644 --- a/modules/juce_graphics/colour/juce_Colour.h +++ b/modules/juce_graphics/colour/juce_Colour.h @@ -136,6 +136,17 @@ public: float brightness, float alpha) noexcept; + /** Creates a colour using floating point hue, saturation, brightness values, and an 8-bit alpha. + + All values must be between 0.0 and 1.0. + An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. + Numbers outside the valid range will be clipped. + */ + static Colour fromHSV (float hue, + float saturation, + float brightness, + uint8 alpha) noexcept; + /** Creates a colour using floating point hue, saturation, lightness and alpha values. All values must be between 0.0 and 1.0. @@ -146,6 +157,17 @@ public: float lightness, float alpha) noexcept; + /** Creates a colour using floating point hue, saturation, lightness values, and an 8-bit alpha. + + All values must be between 0.0 and 1.0. + An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. + Numbers outside the valid range will be clipped. + */ + static Colour fromHSL (float hue, + float saturation, + float lightness, + uint8 alpha) noexcept; + /** Creates a colour using a PixelARGB object. This function assumes that the argb pixel is not premultiplied. */