mod colourmaps;
mod scheme;
pub use colourmaps::*;
pub use scheme::{ColourScheme, DivergingGradient, LinearGradientSvg, SequentialGradient};
use std::str::FromStr;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Colour {
red: u8,
green: u8,
blue: u8,
}
impl Colour {
#[deprecated(since = "0.1.1", note = "renamed to `from_rgb`")]
pub const fn new(red: u8, green: u8, blue: u8) -> Self {
Self::from_rgb(red, green, blue)
}
pub const fn from_rgb(red: u8, green: u8, blue: u8) -> Self {
Self { red, green, blue }
}
fn interpolate(self, rhs: Self, ratio: f64) -> Self {
let ratio = ratio.clamp(0.0, 1.0);
let interpolate = |pre: u8, post: u8| {
let pre = pre as f64;
let post = post as f64;
let diff = post - pre;
(pre + (diff * ratio)).round() as u8
};
Colour {
red: interpolate(self.red, rhs.red),
green: interpolate(self.green, rhs.green),
blue: interpolate(self.blue, rhs.blue),
}
}
}
impl std::fmt::Display for Colour {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#{:02X}{:02X}{:02X}", self.red, self.green, self.blue)
}
}
impl FromStr for Colour {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim_start_matches('#');
let len = s.len();
if len != 6 {
return Err(format!("expected 6 characters, got {}", len));
}
let red = u8::from_str_radix(&s[0..2], 16).map_err(|e| e.to_string())?;
let green = u8::from_str_radix(&s[2..4], 16).map_err(|e| e.to_string())?;
let blue = u8::from_str_radix(&s[4..6], 16).map_err(|e| e.to_string())?;
Ok(Colour { red, green, blue })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_colour_interpolation() {
let black = Colour::from_rgb(0, 0, 0);
let white = Colour::from_rgb(255, 255, 255);
assert_eq!(black.interpolate(white, 1.0), white);
assert_eq!(black.interpolate(white, 0.0), black);
assert_eq!(white.interpolate(black, 1.0), black);
assert_eq!(white.interpolate(black, 0.0), white);
assert_eq!(black.interpolate(white, 0.2), Colour::from_rgb(51, 51, 51));
assert_eq!(
white.interpolate(black, 0.2),
Colour::from_rgb(204, 204, 204)
);
let other = Colour::from_rgb(34, 202, 117);
assert_eq!(black.interpolate(other, 0.4), Colour::from_rgb(14, 81, 47));
assert_eq!(
white.interpolate(other, 0.2),
Colour::from_rgb(211, 244, 227)
);
assert_eq!(
white.interpolate(other, 0.8),
Colour::from_rgb(78, 213, 145)
);
}
}