Skip to main content

rust_pdf_box/content/
color.rs

1/// Represents a color in RGB, CMYK, or Grayscale color spaces.
2#[derive(Debug, Clone, Copy, PartialEq)]
3pub enum Color {
4    Rgb(f64, f64, f64),
5    Cmyk(f64, f64, f64, f64),
6    Gray(f64),
7}
8
9impl Color {
10    pub const BLACK: Color = Color::Gray(0.0);
11    pub const WHITE: Color = Color::Gray(1.0);
12    pub const RED: Color = Color::Rgb(1.0, 0.0, 0.0);
13    pub const GREEN: Color = Color::Rgb(0.0, 1.0, 0.0);
14    pub const BLUE: Color = Color::Rgb(0.0, 0.0, 1.0);
15    pub const GRAY: Color = Color::Gray(0.5);
16
17    pub fn rgb(r: f64, g: f64, b: f64) -> Self {
18        Self::Rgb(r.clamp(0.0, 1.0), g.clamp(0.0, 1.0), b.clamp(0.0, 1.0))
19    }
20
21    pub fn cmyk(c: f64, m: f64, y: f64, k: f64) -> Self {
22        Self::Cmyk(
23            c.clamp(0.0, 1.0),
24            m.clamp(0.0, 1.0),
25            y.clamp(0.0, 1.0),
26            k.clamp(0.0, 1.0),
27        )
28    }
29
30    pub fn gray(g: f64) -> Self {
31        Self::Gray(g.clamp(0.0, 1.0))
32    }
33
34    /// Parses a hex color string like "#FF0000" or "FF0000".
35    pub fn from_hex(hex: &str) -> Option<Self> {
36        let s = hex.trim_start_matches('#');
37        if s.len() == 6 {
38            let r = u8::from_str_radix(&s[0..2], 16).ok()? as f64 / 255.0;
39            let g = u8::from_str_radix(&s[2..4], 16).ok()? as f64 / 255.0;
40            let b = u8::from_str_radix(&s[4..6], 16).ok()? as f64 / 255.0;
41            Some(Self::rgb(r, g, b))
42        } else if s.len() == 3 {
43            let r = u8::from_str_radix(&s[0..1].repeat(2), 16).ok()? as f64 / 255.0;
44            let g = u8::from_str_radix(&s[1..2].repeat(2), 16).ok()? as f64 / 255.0;
45            let b = u8::from_str_radix(&s[2..3].repeat(2), 16).ok()? as f64 / 255.0;
46            Some(Self::rgb(r, g, b))
47        } else {
48            None
49        }
50    }
51}