#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub struct Color {
pub r: u16,
pub g: u16,
pub b: u16,
}
impl Color {
pub fn rgb(r: u16, g: u16, b: u16) -> Self {
Self { r, g, b }
}
pub fn perceived_lightness(&self) -> f32 {
let color = xterm_color::Color::rgb(self.r, self.g, self.b);
color.perceived_lightness()
}
pub fn scale_to_8bit(&self) -> (u8, u8, u8) {
(
scale_to_u8(self.r),
scale_to_u8(self.g),
scale_to_u8(self.b),
)
}
}
fn scale_to_u8(channel: u16) -> u8 {
(channel as u32 * (u8::MAX as u32) / (u16::MAX as u32)) as u8
}
#[cfg(feature = "rgb")]
impl From<Color> for rgb::RGB16 {
fn from(value: Color) -> Self {
rgb::RGB16 {
r: value.r,
g: value.g,
b: value.b,
}
}
}
#[cfg(feature = "rgb")]
impl From<Color> for rgb::RGB8 {
fn from(value: Color) -> Self {
let (r, g, b) = value.scale_to_8bit();
rgb::RGB8 { r, g, b }
}
}
#[cfg(feature = "rgb")]
impl From<rgb::RGB16> for Color {
fn from(value: rgb::RGB16) -> Self {
Color {
r: value.r,
g: value.g,
b: value.b,
}
}
}
#[cfg(feature = "anstyle")]
impl From<Color> for anstyle::RgbColor {
fn from(value: Color) -> Self {
let (r, g, b) = value.scale_to_8bit();
anstyle::RgbColor(r, g, b)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn black_has_perceived_lightness_zero() {
let black = Color::default();
assert_eq!(0.0, black.perceived_lightness())
}
#[test]
fn white_has_perceived_lightness_100() {
let white = Color {
r: u16::MAX,
g: u16::MAX,
b: u16::MAX,
};
assert_eq!(1.0, white.perceived_lightness())
}
}