use crate::{compsci::colours::cmyk::CMYK, math::general::Averages};
#[derive(Clone, Copy, PartialEq)]
pub struct RGBa {
pub red: u8,
pub green: u8,
pub blue: u8,
pub alpha: u8
}
impl RGBa {
#[inline]
#[must_use]
pub const fn new(red: u8, green: u8, blue: u8, alpha: u8) -> RGBa {
RGBa { red, green, blue, alpha }
}
#[inline]
#[must_use]
pub fn from_str(s: &str) -> RGBa {
if s.len() != 8
{ panic!("String did not have the required length of 8."); }
let mut vals: Vec<u8> = Vec::with_capacity(4);
for _s in s.as_bytes().chunks(2) {
let mut r = String::with_capacity(2);
r.push(_s[0] as char);
r.push(_s[1] as char);
vals.push(u8::from_str_radix(&r, 16).unwrap());
}
RGBa { red: vals[0],
green: vals[1],
blue: vals[2],
alpha: vals[3] }
}
#[inline]
#[must_use]
pub fn from_cmyk_struct(cmyk: &CMYK) -> RGBa {
RGBa { red: (255.0 * (1.0 - cmyk.cyan()) * (1.0 - cmyk.black())).round() as u8,
green: (255.0 * (1.0 - cmyk.magenta()) * (1.0 - cmyk.black())).round() as u8,
blue: (255.0 * (1.0 - cmyk.yellow()) * (1.0 - cmyk.black())).round() as u8,
alpha: 255 }
}
#[inline]
#[must_use]
pub const fn is_transparent(&self) -> bool {
!self.is_opaque()
}
#[inline]
#[must_use]
pub const fn is_opaque(&self) -> bool {
self.alpha == 255
}
pub fn to_string_no_alpha(&self) -> String {
let mut res = self.to_string();
res.drain((res.len() - 2)..res.len());
res
}
#[inline]
#[must_use]
pub fn from_cmyk_vals(cyan: f32,
magenta: f32,
yellow: f32,
black: f32) -> RGBa {
RGBa::from_cmyk_struct(&CMYK::new(cyan, magenta, yellow, black))
}
pub const SOLID_RED: RGBa = RGBa { red: 255, green: 0, blue: 0, alpha: 255};
pub const SOLID_GREEN: RGBa = RGBa { red: 0, green: 255, blue: 0, alpha: 255};
pub const SOLID_BLUE: RGBa = RGBa { red: 0, green: 0, blue: 255, alpha: 255};
pub const SOLID_WHITE: RGBa = RGBa { red: 255, green: 255, blue: 255, alpha: 255};
pub const SOLID_BLACK: RGBa = RGBa { red: 0, green: 0, blue: 0, alpha: 255};
pub const LIBRAPID_SOLID_BLUE: RGBa = RGBa { red: 144, green: 116, blue: 255, alpha: 255};
pub const LIBRAPID_SOLID_RED: RGBa = RGBa { red: 255, green: 54, blue: 0, alpha: 255};
}
impl std::fmt::Debug for RGBa {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Red: {}; Blue: {}; Green: {}; Alpha: {}", self.red,
self.green,
self.blue,
self.alpha)
}
}
impl std::fmt::Display for RGBa {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#{:02X}{:02X}{:02X}{:02X}", self.red, self.green, self.blue, self.alpha)
}
}
impl IntoIterator for RGBa {
type Item = u8;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
vec![self.red, self.green, self.blue, self.alpha].into_iter()
}
}
impl<T: std::convert::From<f32>> Averages<T> for RGBa {
type Output = f32;
fn arithmetic_mean(&self) -> Self::Output {
vec![self.red as f32, self.green as f32, self.blue as f32].arithmetic_mean()
}
fn harmonic_mean(&self) -> Self::Output {
vec![self.red as f32, self.green as f32, self.blue as f32].harmonic_mean()
}
fn median(&self) -> Self::Output {
vec![self.red, self.green, self.blue].median()
}
fn mode(&self) -> T {
vec![self.red as f32, self.green as f32, self.blue as f32].mode().into()
}
fn mid_range(&self) -> Self::Output {
vec![self.red as f32, self.green as f32, self.blue as f32].mid_range()
}
}