use std::fmt; /// Represents a color in the RGB (Red, Green, Blue) model. /// Values range from 0 to 255. pub struct Rgb { pub r: u8, pub g: u8, pub b: u8, } /// Represents a color in the HSV (Hue, Saturation, Value) model. /// - `h` (hue): 0-359 degrees /// - `s` (saturation): 0.0-1.0 /// - `v` (value/brightness): 0.0-1.0 pub struct Hsv { pub h: u16, pub s: f32, pub v: f32, } // Implement the `Debug` trait for Rgb to allow pretty-printing. impl fmt::Debug for Rgb { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Rgb({}, {}, {})", self.r, self.g, self.b) } } /// Provides the conversion logic from HSV to RGB. /// This uses the standard mathematical formula for the conversion. impl From for Rgb { fn from(hsv: Hsv) -> Self { // Ensure saturation and value are within the valid range [0.0, 1.0] let s = hsv.s.clamp(0.0, 1.0); let v = hsv.v.clamp(0.0, 1.0); // When saturation is 0, the color is a shade of gray. if s == 0.0 { let val = (v * 255.0) as u8; return Rgb { r: val, g: val, b: val }; } // The hue is treated as a sector on a color wheel. let h = hsv.h as f32 / 60.0; // Sector 0-5 let i = h.floor() as i32; let f = h - i as f32; // Fractional part of h let p = v * (1.0 - s); let q = v * (1.0 - f * s); let t = v * (1.0 - (1.0 - f) * s); // Determine the RGB values based on the hue sector. let (r, g, b) = match i { 0 => (v, t, p), 1 => (q, v, p), 2 => (p, v, t), 3 => (p, q, v), 4 => (t, p, v), _ => (v, p, q), // Default case for sector 5 }; // Convert the float RGB values (0.0-1.0) to u8 values (0-255). Rgb { r: (r * 255.0).round() as u8, g: (g * 255.0).round() as u8, b: (b * 255.0).round() as u8, } } }