1use crate::error::DrawError;
6
7#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct Color {
10 pub r: u8,
12 pub g: u8,
14 pub b: u8,
16 pub a: u8,
18}
19
20impl Color {
21 pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
23 Self { r, g, b, a }
24 }
25
26 pub fn rgb(r: u8, g: u8, b: u8) -> Self {
28 Self::new(r, g, b, 255)
29 }
30
31 pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
33 Self::new(r, g, b, a)
34 }
35
36 pub fn from_hex(hex: &str) -> Result<Self, DrawError> {
39 let hex = hex.trim_start_matches('#');
40
41 match hex.len() {
42 3 => {
43 let r = u8::from_str_radix(&hex[0..1].repeat(2), 16)
45 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
46 let g = u8::from_str_radix(&hex[1..2].repeat(2), 16)
47 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
48 let b = u8::from_str_radix(&hex[2..3].repeat(2), 16)
49 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
50 Ok(Self::rgb(r, g, b))
51 }
52 4 => {
53 let r = u8::from_str_radix(&hex[0..1].repeat(2), 16)
55 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
56 let g = u8::from_str_radix(&hex[1..2].repeat(2), 16)
57 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
58 let b = u8::from_str_radix(&hex[2..3].repeat(2), 16)
59 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
60 let a = u8::from_str_radix(&hex[3..4].repeat(2), 16)
61 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
62 Ok(Self::rgba(r, g, b, a))
63 }
64 6 => {
65 let r = u8::from_str_radix(&hex[0..2], 16)
67 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
68 let g = u8::from_str_radix(&hex[2..4], 16)
69 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
70 let b = u8::from_str_radix(&hex[4..6], 16)
71 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
72 Ok(Self::rgb(r, g, b))
73 }
74 8 => {
75 let r = u8::from_str_radix(&hex[0..2], 16)
77 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
78 let g = u8::from_str_radix(&hex[2..4], 16)
79 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
80 let b = u8::from_str_radix(&hex[4..6], 16)
81 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
82 let a = u8::from_str_radix(&hex[6..8], 16)
83 .map_err(|_| DrawError::InvalidColor(format!("Invalid hex color: #{}", hex)))?;
84 Ok(Self::rgba(r, g, b, a))
85 }
86 _ => Err(DrawError::InvalidColor(format!("Invalid hex color length: #{}", hex))),
87 }
88 }
89
90 pub fn to_rgba(&self) -> image::Rgba<u8> {
92 image::Rgba([self.r, self.g, self.b, self.a])
93 }
94
95 pub fn from_rgba(rgba: image::Rgba<u8>) -> Self {
97 Self::new(rgba[0], rgba[1], rgba[2], rgba[3])
98 }
99
100 pub const WHITE: Color = Color { r: 255, g: 255, b: 255, a: 255 };
102 pub const BLACK: Color = Color { r: 0, g: 0, b: 0, a: 255 };
103 pub const RED: Color = Color { r: 255, g: 0, b: 0, a: 255 };
104 pub const GREEN: Color = Color { r: 0, g: 255, b: 0, a: 255 };
105 pub const BLUE: Color = Color { r: 0, g: 0, b: 255, a: 255 };
106 pub const YELLOW: Color = Color { r: 255, g: 255, b: 0, a: 255 };
107 pub const CYAN: Color = Color { r: 0, g: 255, b: 255, a: 255 };
108 pub const MAGENTA: Color = Color { r: 255, g: 0, b: 255, a: 255 };
109 pub const TRANSPARENT: Color = Color { r: 0, g: 0, b: 0, a: 0 };
110 pub const GRAY: Color = Color { r: 128, g: 128, b: 128, a: 255 };
111}
112
113impl Default for Color {
114 fn default() -> Self {
115 Self::BLACK
116 }
117}
118
119impl From<(u8, u8, u8)> for Color {
120 fn from((r, g, b): (u8, u8, u8)) -> Self {
121 Self::rgb(r, g, b)
122 }
123}
124
125impl From<(u8, u8, u8, u8)> for Color {
126 fn from((r, g, b, a): (u8, u8, u8, u8)) -> Self {
127 Self::rgba(r, g, b, a)
128 }
129}
130
131impl From<image::Rgba<u8>> for Color {
132 fn from(rgba: image::Rgba<u8>) -> Self {
133 Self::from_rgba(rgba)
134 }
135}
136
137impl From<Color> for image::Rgba<u8> {
138 fn from(color: Color) -> Self {
139 color.to_rgba()
140 }
141}