diff options
author | 2020-02-21 16:42:12 -0600 | |
---|---|---|
committer | 2020-04-24 15:13:22 -0500 | |
commit | 0ff3cbf543e84b1e4d1965efe3d6cce3b1fb5900 (patch) | |
tree | 643cd37883b4cbb456f3062b614e08b4871e6795 /core | |
parent | 27a4cbccea91c508b914f2211a07aec2a4bed96e (diff) | |
download | iced-0ff3cbf543e84b1e4d1965efe3d6cce3b1fb5900.tar.gz iced-0ff3cbf543e84b1e4d1965efe3d6cce3b1fb5900.tar.bz2 iced-0ff3cbf543e84b1e4d1965efe3d6cce3b1fb5900.zip |
HSLColor struct, with conversions to/from RGB
Diffstat (limited to 'core')
-rw-r--r-- | core/src/color.rs | 122 |
1 files changed, 106 insertions, 16 deletions
diff --git a/core/src/color.rs b/core/src/color.rs index fbc160e3..a46f44ee 100644 --- a/core/src/color.rs +++ b/core/src/color.rs @@ -36,18 +36,13 @@ impl Color { a: 0.0, }; - /// Calmps a float value to the range [0.0, 1.0] - pub fn clamp(v: f32) -> f32 { - v.max(0.0f32).min(1.0f32) - } - - /// Ensures RGBA values on the range [0.0, 1.0] + /// New Color with range checks pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color { Color { - r: Color::clamp(r), - g: Color::clamp(g), - b: Color::clamp(b), - a: Color::clamp(a), + r: clamp(r), + g: clamp(g), + b: clamp(b), + a: clamp(a), } } @@ -73,7 +68,7 @@ impl Color { r: f32::from(r) / 255.0, g: f32::from(g) / 255.0, b: f32::from(b) / 255.0, - a: Color::clamp(a), + a: clamp(a), } } @@ -101,9 +96,9 @@ impl Color { /// Invert the Color in-place pub fn invert(&mut self) { - self.r = Color::clamp(1.0f32 - self.r); - self.b = Color::clamp(1.0f32 - self.g); - self.g = Color::clamp(1.0f32 - self.b); + self.r = clamp(1.0f32 - self.r); + self.b = clamp(1.0f32 - self.g); + self.g = clamp(1.0f32 - self.b); } /// Return an inverted Color @@ -114,12 +109,107 @@ impl Color { impl From<[f32; 3]> for Color { fn from([r, g, b]: [f32; 3]) -> Self { - Color { r, g, b, a: 1.0 } + Color::new(r, g, b, 1.0) } } impl From<[f32; 4]> for Color { fn from([r, g, b, a]: [f32; 4]) -> Self { - Color { r, g, b, a } + Color::new(r, g, b, a) + } +} + +impl From<HSLColor> for Color { + fn from(hsl: HSLColor) -> Self { + // Compute Chroma + let ch = (1.0 - (2.0 * hsl.l - 1.0).abs()) * hsl.s; + + // Quantized Hue: H' + let hp: u8 = (hsl.h / 60.0).ceil() as u8; + let x: f32 = ch * f32::from(1 - ((hp % 2) - 1)); + + // Intermediate RGB values + let (r1, g1, b1): (f32, f32, f32) = match hp { + 1 => (ch, x, 0.0), + 2 => (x, ch, 0.0), + 3 => (0.0, ch, x), + 4 => (0.0, x, ch), + 5 => (x, 0.0, ch), + 6 => (ch, 0.0, x), + _ => (0.0, 0.0, 0.0), + }; + + // Match lightness + let m = hsl.l - ch / 2.0; + + Color::new(r1 + m, g1 + m, b1 + m, hsl.a) + } +} + +/// A color in the HSL color space. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct HSLColor { + /// Hue, 0.0 - 360.0 + pub h: f32, + /// Saturation, 0.0 - 1.0 + pub s: f32, + /// Lightness, 0.0 - 1.0 + pub l: f32, + /// Transparency, 0.0 - 1.0 + pub a: f32, +} + +impl HSLColor { + /// New HSLColor with range checks + pub fn new(h: f32, s: f32, l: f32, a: f32) -> HSLColor { + HSLColor { + h: clamp_hue(h), + s: clamp(s), + l: clamp(l), + a: clamp(a), + } + } +} + +impl From<Color> for HSLColor { + fn from(c: Color) -> Self { + // https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB + + // Maximum of the RGB: color Value (for HSV) + let v: f32 = c.r.max(c.g).max(c.b); + // Minimum of the RGB values + let m: f32 = c.r.min(c.g).min(c.b); + // Chroma + let ch: f32 = v - m; + // Lightness + let l: f32 = (v + m) / 2.0; + + // Determine Hue + let mut h = 0.0f32; + if c.r >= c.g && c.r >= c.b { + h = 60.0 * (c.g - c.b) / ch; + } else if c.g >= c.r && c.g >= c.b { + h = 60.0 * (2.0 + (c.b - c.r) / ch); + } else if c.b >= c.r && c.b >= c.g { + h = 60.0 * (4.0 + (c.r - c.g) / ch); + } + + // Determine saturation + let mut s = 0.0f32; + if l > 0.0 && l < 1.0 { + s = (v - l) / l.min(1.0 - l); + } + + HSLColor::new(h, s, l, c.a) } } + +/// Calmps a float value to the range [0.0, 1.0] +pub fn clamp(v: f32) -> f32 { + v.max(0.0f32).min(1.0f32) +} + +/// Calmps a float value to the range [0.0, 360.0] +pub fn clamp_hue(v: f32) -> f32 { + v.max(0.0f32).min(360.0f32) +} |