mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Added HSL support to Colour and use Colour::fromHSL() when parsing SVG HSL colours
This commit is contained in:
parent
69469068a9
commit
7553b8dc1b
4 changed files with 395 additions and 88 deletions
|
|
@ -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" };
|
||||
|
|
|
|||
|
|
@ -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<uint8> (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<uint8> ((col >> 24) & 0xff),
|
||||
static_cast<uint8> ((col >> 16) & 0xff),
|
||||
static_cast<uint8> ((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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue