use crate::color_space::ColorSpace;
use crate::color_value::{CmykColor, LabColor, RgbColor};
fn clamp(value: f32, min: f32, max: f32) -> f32 {
if value < min {
min
} else if value > max {
max
} else {
value
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct XyzColor {
x: f32,
y: f32,
z: f32,
}
impl XyzColor {
pub fn new(x: f32, y: f32, z: f32) -> Self {
Self {
x: clamp(x, 0.0, 1.0),
y: clamp(y, 0.0, 1.0),
z: clamp(z, 0.0, 1.0),
}
}
pub fn x(&self) -> f32 { self.x }
pub fn y(&self) -> f32 { self.y }
pub fn z(&self) -> f32 { self.z }
pub fn to_array(&self) -> [f32; 3] { [self.x, self.y, self.z] }
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GrayColor {
v: f32,
}
impl GrayColor {
pub fn new(value: f32) -> Self {
Self {
v: clamp(value, 0.0, 1.0),
}
}
pub fn value(&self) -> f32 { self.v }
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ColorValue {
Rgb(RgbColor),
Cmyk(CmykColor),
Lab(LabColor),
Xyz(XyzColor),
Gray(GrayColor),
}
impl ColorValue {
pub fn color_space(&self) -> ColorSpace {
match self {
ColorValue::Rgb(_) => ColorSpace::Rgb,
ColorValue::Cmyk(_) => ColorSpace::Cmyk,
ColorValue::Lab(_) => ColorSpace::Lab,
ColorValue::Xyz(_) => ColorSpace::Xyz,
ColorValue::Gray(_) => ColorSpace::Gray,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn xyz_clamps_on_construction() {
let c = XyzColor::new(1.5, -0.1, 0.5);
assert_eq!(c.x(), 1.0);
assert_eq!(c.y(), 0.0);
assert_eq!(c.z(), 0.5);
}
#[test]
fn gray_clamps_on_construction() {
assert_eq!(GrayColor::new(2.0).value(), 1.0);
assert_eq!(GrayColor::new(-1.0).value(), 0.0);
}
#[test]
fn color_value_space_detection() {
let rgb = ColorValue::Rgb(RgbColor::new(0.0, 0.0, 0.0));
assert_eq!(rgb.color_space(), ColorSpace::Rgb);
let cmyk = ColorValue::Cmyk(CmykColor::new(0.0, 0.0, 0.0, 0.0));
assert_eq!(cmyk.color_space(), ColorSpace::Cmyk);
let lab = ColorValue::Lab(LabColor::new(0.0, 0.0, 0.0));
assert_eq!(lab.color_space(), ColorSpace::Lab);
let xyz = ColorValue::Xyz(XyzColor::new(0.0, 0.0, 0.0));
assert_eq!(xyz.color_space(), ColorSpace::Xyz);
let gray = ColorValue::Gray(GrayColor::new(0.0));
assert_eq!(gray.color_space(), ColorSpace::Gray);
}
}