use super::{
error::ColorConversionError,
hex::hex_to_rgb,
rgb::rgb_to_hex,
validate::validate_hex,
};
pub fn rgb_from_color_definition<T>(input: T) -> Result<[u8; 3], ColorConversionError>
where
T: IntoRgb,
{
input.into_rgb()
}
pub trait IntoRgb {
fn into_rgb(self) -> Result<[u8; 3], ColorConversionError>;
}
impl IntoRgb for [u8; 3] {
fn into_rgb(self) -> Result<[u8; 3], ColorConversionError> {
Ok(self)
}
}
impl IntoRgb for String {
fn into_rgb(self) -> Result<[u8; 3], ColorConversionError> {
validate_hex(&self)?;
Ok(hex_to_rgb(&self))
}
}
impl IntoRgb for &str {
fn into_rgb(self) -> Result<[u8; 3], ColorConversionError> {
validate_hex(self)?;
Ok(hex_to_rgb(self))
}
}
impl IntoRgb for u8 {
fn into_rgb(self) -> Result<[u8; 3], ColorConversionError> {
Ok(ansi8_to_rgb(self))
}
}
pub fn ansi8_to_rgb(num: u8) -> [u8; 3] {
match num {
0..=6 => {
let mut bits = format!("{:03b}", num)
.chars()
.rev()
.map(|c| c.to_digit(2).unwrap())
.map(|b| (b * 255 / 2) as u8)
.collect::<Vec<_>>();
while bits.len() < 3 {
bits.push(0);
}
[bits[0], bits[1], bits[2]]
}
7 => [192, 192, 192], 8 => [127, 127, 127], 9..=15 => {
let bits = format!("{:03b}", num - 8)
.chars()
.rev()
.map(|c| c.to_digit(2).unwrap())
.map(|b| (b * 255) as u8)
.collect::<Vec<_>>();
[bits[0], bits[1], bits[2]]
}
16..=231 => {
let index = num - 16;
let r = index / 36;
let g = (index / 6) % 6;
let b = index % 6;
let scale = |x: u8| {
if x == 0 {
0
} else {
(x as u16 * 200 / 5 + 55) as u8
}
};
[scale(r), scale(g), scale(b)]
}
232..=255 => {
let gray = ((num - 231) as u16 * 240 / 24).saturating_sub(2) as u8;
[gray, gray, gray]
} }
}
pub fn ansi8_to_hex(num: u8) -> String {
let rgb = ansi8_to_rgb(num);
rgb_to_hex(rgb)
}