29namespace ColourHelpers
31 static uint8 floatToUInt8 (
float n)
noexcept
33 return n <= 0.0f ? 0 : (n >= 1.0f ? 255 : (
uint8)
roundToInt (n * 255.0f));
36 static float getHue (Colour col)
38 auto r = (
int) col.getRed();
39 auto g = (
int) col.getGreen();
40 auto b = (
int) col.getBlue();
42 auto hi =
jmax (r, g, b);
43 auto lo =
jmin (r, g, b);
49 auto invDiff = 1.0f / (
float) (hi - lo);
51 auto red = (
float) (hi - r) * invDiff;
52 auto green = (
float) (hi - g) * invDiff;
53 auto blue = (
float) (hi - b) * invDiff;
55 if (r == hi) hue = blue - green;
56 else if (g == hi) hue = 2.0f + red - blue;
57 else hue = 4.0f + green - red;
77 auto hi =
jmax (r, g, b);
78 auto lo =
jmin (r, g, b);
83 lightness = ((
float) (hi + lo) / 2.0f) / 255.0f;
85 if (lightness <= 0.0f)
90 if (1.0f <= lightness)
93 auto denominator = 1.0f - std::abs ((2.0f * lightness) - 1.0f);
94 saturation = ((
float) (hi - lo) / 255.0f) / denominator;
102 static PixelARGB toRGB (
float h,
float s,
float l,
uint8 alpha)
noexcept
104 auto v = l < 0.5f ? l * (1.0f + s) : l + s - (l * s);
109 auto min = (2.0f * l) - v;
110 auto sv = (v - min) / v;
114 auto vsf = v * sv * f;
115 auto mid1 = min + vsf;
118 if (h < 1.0f)
return PixelARGB (alpha, floatToUInt8 (v), floatToUInt8 (mid1), floatToUInt8 (min));
119 else if (h < 2.0f)
return PixelARGB (alpha, floatToUInt8 (mid2), floatToUInt8 (v), floatToUInt8 (min));
120 else if (h < 3.0f)
return PixelARGB (alpha, floatToUInt8 (min), floatToUInt8 (v), floatToUInt8 (mid1));
121 else if (h < 4.0f)
return PixelARGB (alpha, floatToUInt8 (min), floatToUInt8 (mid2), floatToUInt8 (v));
122 else if (h < 5.0f)
return PixelARGB (alpha, floatToUInt8 (mid1), floatToUInt8 (min), floatToUInt8 (v));
123 else if (h < 6.0f)
return PixelARGB (alpha, floatToUInt8 (v), floatToUInt8 (min), floatToUInt8 (mid2));
128 float hue = 0.0f, saturation = 0.0f, lightness = 0.0f;
140 auto hi =
jmax (r, g, b);
141 auto lo =
jmin (r, g, b);
147 if (saturation > 0.0f)
150 brightness = (
float) hi / 255.0f;
159 static PixelARGB toRGB (
float h,
float s,
float v,
uint8 alpha)
noexcept
161 v =
jlimit (0.0f, 255.0f, v * 255.0f);
165 return PixelARGB (alpha, intV, intV, intV);
180 float hue = 0.0f, saturation = 0.0f, brightness = 0.0f;
192 y = 0.2999f * r + 0.5870f * g + 0.1140f * b;
193 i = 0.5957f * r - 0.2744f * g - 0.3212f * b;
194 q = 0.2114f * r - 0.5225f * g - 0.3113f * b;
198 Colour toColour()
const noexcept
201 y - 0.2721f * i - 0.6474f * q,
202 y - 1.1070f * i + 1.7046f * q,
206 float y = 0.0f, i = 0.0f, q = 0.0f, alpha = 0.0f;
216 : argb (
static_cast<uint8> ((col >> 24) & 0xff),
217 static_cast<uint8> ((col >> 16) & 0xff),
218 static_cast<uint8> ((col >> 8) & 0xff),
219 static_cast<uint8> (col & 0xff))
225 argb.setARGB (0xff, red, green, blue);
230 return Colour (red, green, blue);
235 argb.setARGB (alpha, red, green, blue);
240 return Colour (red, green, blue, alpha);
245 argb.setARGB (ColourHelpers::floatToUInt8 (alpha), red, green, blue);
250 return Colour (ColourHelpers::floatToUInt8 (red),
251 ColourHelpers::floatToUInt8 (green),
252 ColourHelpers::floatToUInt8 (blue), alpha);
255Colour::Colour (
float hue,
float saturation,
float brightness,
float alpha) noexcept
256 : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, ColourHelpers::floatToUInt8 (alpha)))
262 return Colour (hue, saturation, brightness, alpha);
268 hslColour.argb = ColourHelpers::HSL::toRGB (hue, saturation, lightness, ColourHelpers::floatToUInt8 (alpha));
274 : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, alpha))
284 : argb (
Colour (rgb.getInARGBMaskOrder()).argb)
289 : argb (
Colour (alpha.getInARGBMaskOrder()).argb)
331 jassert (newAlpha >= 0 && newAlpha <= 1.0f);
334 newCol.
setAlpha (ColourHelpers::floatToUInt8 (newAlpha));
340 jassert (alphaMultiplier >= 0);
350 auto destAlpha = getAlpha();
355 auto invA = 0xff - (
int) src.getAlpha();
356 auto resA = 0xff - (((0xff - destAlpha) * invA) >> 8);
361 auto da = (invA * destAlpha) / resA;
363 return Colour ((
uint8) (src.getRed() + ((((
int) getRed() - src.getRed()) * da) >> 8)),
364 (
uint8) (src.getGreen() + ((((
int) getGreen() - src.getGreen()) * da) >> 8)),
365 (
uint8) (src.getBlue() + ((((
int) getBlue() - src.getBlue()) * da) >> 8)),
371 if (proportionOfOther <= 0)
374 if (proportionOfOther >= 1.0f)
433 hsb.hue += amountToRotate;
434 return hsb.toColour (*
this);
440 hsb.saturation =
jmin (1.0f, hsb.saturation * amount);
441 return hsb.toColour (*
this);
447 hsl.saturation =
jmin (1.0f, hsl.saturation * amount);
448 return hsl.toColour (*
this);
454 hsb.brightness =
jmin (1.0f, hsb.brightness * amount);
455 return hsb.toColour (*
this);
461 hsl.lightness =
jmin (1.0f, hsl.lightness * amount);
462 return hsl.toColour (*
this);
469 amount = 1.0f / (1.0f + amount);
471 return Colour ((
uint8) (255 - (amount * (255 - getRed()))),
472 (
uint8) (255 - (amount * (255 - getGreen()))),
473 (
uint8) (255 - (amount * (255 - getBlue()))),
480 amount = 1.0f / (1.0f + amount);
483 (
uint8) (amount * getGreen()),
484 (
uint8) (amount * getBlue()),
491 auto level = ColourHelpers::floatToUInt8 (brightness);
492 return Colour (level, level, level);
498 return overlaidWith ((getPerceivedBrightness() >= 0.5f
500 : Colours::white).withAlpha (amount));
508 if (std::abs (bg.y - fg.y) >= minContrast)
511 auto y1 =
jmax (0.0f, bg.y - minContrast);
512 auto y2 =
jmin (1.0f, bg.y + minContrast);
513 fg.y = (std::abs (
y1 - bg.y) > std::abs (y2 - bg.y)) ?
y1 : y2;
515 return fg.toColour();
522 auto b2 = colour2.getPerceivedBrightness();
523 float best = 0.0f, bestDist = 0.0f;
525 for (
float i = 0.0f; i < 1.0f; i += 0.02f)
527 auto d1 = std::abs (i - b1);
528 auto d2 = std::abs (i - b2);
529 auto dist =
jmin (d1, d2, 1.0f - d1, 1.0f - d2);
538 return colour1.overlaidWith (colour2.withMultipliedAlpha (0.5f))
539 .withBrightness (best);
556 .paddedLeft (
'0', includeAlphaValue ? 8 : 6)
565class ColourTests final :
public UnitTest
569 :
UnitTest (
"Colour", UnitTestCategories::graphics)
572 void runTest()
override
574 auto testColour = [
this] (Colour colour,
575 uint8 expectedRed, uint8 expectedGreen, uint8 expectedBlue,
576 uint8 expectedAlpha = 255,
float expectedFloatAlpha = 1.0f)
578 expectEquals (colour.getRed(), expectedRed);
579 expectEquals (colour.getGreen(), expectedGreen);
580 expectEquals (colour.getBlue(), expectedBlue);
581 expectEquals (colour.getAlpha(), expectedAlpha);
582 expectEquals (colour.getFloatAlpha(), expectedFloatAlpha);
585 beginTest (
"Constructors");
588 testColour (c1, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0, 0.0f);
590 Colour c2 ((uint32) 0);
591 testColour (c2, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0, 0.0f);
593 Colour c3 ((uint32) 0xffffffff);
594 testColour (c3, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255, 1.0f);
597 testColour (c4, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 255, 1.0f);
599 Colour c5 (255, 255, 255);
600 testColour (c5, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255, 1.0f);
602 Colour c6 ((uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0);
603 testColour (c6, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0, 0.0f);
605 Colour c7 ((uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255);
606 testColour (c7, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255, 1.0f);
608 Colour c8 ((uint8) 0, (uint8) 0, (uint8) 0, 0.0f);
609 testColour (c8, (uint8) 0, (uint8) 0, (uint8) 0, (uint8) 0, 0.0f);
611 Colour c9 ((uint8) 255, (uint8) 255, (uint8) 255, 1.0f);
612 testColour (c9, (uint8) 255, (uint8) 255, (uint8) 255, (uint8) 255, 1.0f);
618 testColour (Colour::fromHSV (0.0f, 0.0f, 0.0f, 1.0f), 0, 0, 0);
620 testColour (Colour::fromHSV (0.0f, 0.0f, 1.0f, 1.0f), 255, 255, 255);
622 testColour (Colour::fromHSV (0.0f, 1.0f, 1.0f, 1.0f), 255, 0, 0);
623 testColour (Colour::fromHSV (1.0f, 1.0f, 1.0f, 1.0f), 255, 0, 0);
625 testColour (Colour::fromHSV (120 / 360.0f, 1.0f, 1.0f, 1.0f), 0, 255, 0);
627 testColour (Colour::fromHSV (240 / 360.0f, 1.0f, 1.0f, 1.0f), 0, 0, 255);
629 testColour (Colour::fromHSV (60 / 360.0f, 1.0f, 1.0f, 1.0f), 255, 255, 0);
631 testColour (Colour::fromHSV (180 / 360.0f, 1.0f, 1.0f, 1.0f), 0, 255, 255);
633 testColour (Colour::fromHSV (300 / 360.0f, 1.0f, 1.0f, 1.0f), 255, 0, 255);
635 testColour (Colour::fromHSV (0.0f, 0.0f, 0.75f, 1.0f), 191, 191, 191);
637 testColour (Colour::fromHSV (0.0f, 0.0f, 0.5f, 1.0f), 128, 128, 128);
639 testColour (Colour::fromHSV (0.0f, 1.0f, 0.5f, 1.0f), 128, 0, 0);
641 testColour (Colour::fromHSV (60 / 360.0f, 1.0f, 0.5f, 1.0f), 128, 128, 0);
643 testColour (Colour::fromHSV (120 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 128, 0);
645 testColour (Colour::fromHSV (300 / 360.0f, 1.0f, 0.5f, 1.0f), 128, 0, 128);
647 testColour (Colour::fromHSV (180 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 128, 128);
649 testColour (Colour::fromHSV (240 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 0, 128);
655 testColour (Colour::fromHSL (0.0f, 0.0f, 0.0f, 1.0f), 0, 0, 0);
657 testColour (Colour::fromHSL (0.0f, 0.0f, 1.0f, 1.0f), 255, 255, 255);
659 testColour (Colour::fromHSL (0.0f, 1.0f, 0.5f, 1.0f), 255, 0, 0);
660 testColour (Colour::fromHSL (1.0f, 1.0f, 0.5f, 1.0f), 255, 0, 0);
662 testColour (Colour::fromHSL (120 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 255, 0);
664 testColour (Colour::fromHSL (240 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 0, 255);
666 testColour (Colour::fromHSL (60 / 360.0f, 1.0f, 0.5f, 1.0f), 255, 255, 0);
668 testColour (Colour::fromHSL (180 / 360.0f, 1.0f, 0.5f, 1.0f), 0, 255, 255);
670 testColour (Colour::fromHSL (300 / 360.0f, 1.0f, 0.5f, 1.0f), 255, 0, 255);
672 testColour (Colour::fromHSL (0.0f, 0.0f, 0.75f, 1.0f), 191, 191, 191);
674 testColour (Colour::fromHSL (0.0f, 0.0f, 0.5f, 1.0f), 128, 128, 128);
676 testColour (Colour::fromHSL (0.0f, 1.0f, 0.25f, 1.0f), 128, 0, 0);
678 testColour (Colour::fromHSL (60 / 360.0f, 1.0f, 0.25f, 1.0f), 128, 128, 0);
680 testColour (Colour::fromHSL (120 / 360.0f, 1.0f, 0.25f, 1.0f), 0, 128, 0);
682 testColour (Colour::fromHSL (300 / 360.0f, 1.0f, 0.25f, 1.0f), 128, 0, 128);
684 testColour (Colour::fromHSL (180 / 360.0f, 1.0f, 0.25f, 1.0f), 0, 128, 128);
686 testColour (Colour::fromHSL (240 / 360.0f, 1.0f, 0.25f, 1.0f), 0, 0, 128);
689 beginTest (
"Modifiers");
691 Colour red (255, 0, 0);
692 testColour (red, 255, 0, 0);
694 testColour (red.
withHue (120.0f / 360.0f), 0, 255, 0);
713static ColourTests colourTests;
Represents a colour, also including a transparency value.
uint8 getBlue() const noexcept
Returns the blue component of this colour.
Colour withSaturation(float newSaturation) const noexcept
Returns a copy of this colour with a different saturation.
Colour withAlpha(uint8 newAlpha) const noexcept
Returns a colour that's the same colour as this one, but with a new alpha value.
String toString() const
Returns a stringified version of this colour.
static Colour fromHSL(float hue, float saturation, float lightness, float alpha) noexcept
Creates a colour using floating point hue, saturation, lightness and alpha values.
Colour withLightness(float newLightness) const noexcept
Returns a copy of this colour with a different lightness.
Colour withMultipliedBrightness(float amount) const noexcept
Returns a copy of this colour with its brightness multiplied by the given value.
float getFloatGreen() const noexcept
Returns the green component of this colour as a floating point value.
Colour brighter(float amountBrighter=0.4f) const noexcept
Returns a brighter version of this colour.
float getSaturation() const noexcept
Returns the colour's saturation component.
Colour withMultipliedSaturation(float multiplier) const noexcept
Returns a copy of this colour with its saturation multiplied by the given value.
static Colour fromRGBA(uint8 red, uint8 green, uint8 blue, uint8 alpha) noexcept
Creates a colour using 8-bit red, green, blue and alpha values.
Colour withHue(float newHue) const noexcept
Returns a copy of this colour with a different hue.
Colour darker(float amountDarker=0.4f) const noexcept
Returns a darker version of this colour.
float getFloatBlue() const noexcept
Returns the blue component of this colour as a floating point value.
float getSaturationHSL() const noexcept
Returns the colour's saturation component as represented in the HSL colour space.
float getBrightness() const noexcept
Returns the colour's brightness component.
static Colour greyLevel(float brightness) noexcept
Returns an opaque shade of grey.
static Colour fromString(StringRef encodedColourString)
Reads the colour from a string that was created with toString().
float getLightness() const noexcept
Returns the colour's lightness component.
void getHSL(float &hue, float &saturation, float &lightness) const noexcept
Returns the colour's hue, saturation and lightness components all at once.
PixelARGB getPixelARGB() const noexcept
Returns a premultiplied ARGB pixel object that represents this colour.
Colour withRotatedHue(float amountToRotate) const noexcept
Returns a copy of this colour with its hue rotated.
Colour interpolatedWith(Colour other, float proportionOfOther) const noexcept
Returns a colour that lies somewhere between this one and another.
Colour withMultipliedAlpha(float alphaMultiplier) const noexcept
Returns a colour that's the same colour as this one, but with a modified alpha value.
String toDisplayString(bool includeAlphaValue) const
Returns the colour as a hex string in the form RRGGBB or AARRGGBB.
Colour withSaturationHSL(float newSaturation) const noexcept
Returns a copy of this colour with a different saturation in the HSL colour space.
uint8 getGreen() const noexcept
Returns the green component of this colour.
bool isOpaque() const noexcept
Returns true if this colour is completely opaque.
Colour withMultipliedSaturationHSL(float multiplier) const noexcept
Returns a copy of this colour with its saturation multiplied by the given value.
uint32 getARGB() const noexcept
Returns a 32-bit integer that represents this colour.
static Colour fromRGB(uint8 red, uint8 green, uint8 blue) noexcept
Creates an opaque colour using 8-bit red, green and blue values.
bool operator==(const Colour &other) const noexcept
Compares two colours.
Colour withBrightness(float newBrightness) const noexcept
Returns a copy of this colour with a different brightness.
void getHSB(float &hue, float &saturation, float &brightness) const noexcept
Returns the colour's hue, saturation and brightness components all at once.
PixelARGB getNonPremultipliedPixelARGB() const noexcept
Returns an ARGB pixel object that represents this colour.
uint8 getRed() const noexcept
Returns the red component of this colour.
float getFloatRed() const noexcept
Returns the red component of this colour as a floating point value.
uint8 getAlpha() const noexcept
Returns the colour's alpha (opacity).
static Colour fromHSV(float hue, float saturation, float brightness, float alpha) noexcept
Creates a colour using floating point hue, saturation, brightness and alpha values.
float getFloatAlpha() const noexcept
Returns the colour's alpha (opacity) as a floating point value.
static Colour fromFloatRGBA(float red, float green, float blue, float alpha) noexcept
Creates a colour using floating point red, green, blue and alpha values.
Colour contrasting(float amount=1.0f) const noexcept
Returns a colour that will be clearly visible against this colour.
bool isTransparent() const noexcept
Returns true if this colour is completely transparent.
bool operator!=(const Colour &other) const noexcept
Compares two colours.
Colour()=default
Creates a transparent black colour.
Colour withMultipliedLightness(float amount) const noexcept
Returns a copy of this colour with its lightness multiplied by the given value.
float getHue() const noexcept
Returns the colour's hue component.
float getPerceivedBrightness() const noexcept
Returns a skewed brightness value, adjusted to better reflect the way the human eye responds to diffe...
Colour overlaidWith(Colour foregroundColour) const noexcept
Returns a colour that is the result of alpha-compositing a new colour over this one.
Represents a 32-bit INTERNAL pixel with premultiplied alpha, and can perform compositing operations w...
forcedinline void tween(const Pixel &src, uint32 amount) noexcept
Blends another pixel with this one, creating a colour that is somewhere between the two,...
forcedinline void setAlpha(uint8 newAlpha) noexcept
Replaces the colour's alpha value with another one.
forcedinline void unpremultiply() noexcept
Unpremultiplies the pixel's RGB values.
forcedinline uint32 getInARGBMaskOrder() const noexcept
Returns a uint32 which will be in argb order as if constructed with the following mask operation ((al...
forcedinline void premultiply() noexcept
Premultiplies the pixel's RGB values by its alpha.
Represents an 8-bit single-channel pixel, and can perform compositing operations on it.
Represents a 24-bit RGB pixel, and can perform compositing operations on it.
A simple class for holding temporary references to a string literal or String.
String::CharPointerType text
The text that is referenced.
static String toHexString(IntegerType number)
Returns a string representing this numeric value in hexadecimal.
This is a base class for classes that perform a unit test.
constexpr bool approximatelyEqual(Type a, Type b, Tolerance< Type > tolerance=Tolerance< Type >{} .withAbsolute(std::numeric_limits< Type >::min()) .withRelative(std::numeric_limits< Type >::epsilon()))
Returns true if the two floating-point numbers are approximately equal.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr bool exactlyEqual(Type a, Type b)
Equivalent to operator==, but suppresses float-equality warnings.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
constexpr NumericType square(NumericType n) noexcept
Returns the square of its argument.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
Parses a character string, to read a hexadecimal value.