1use serde::Deserialize;
2use serde::Serialize;
3extern crate alloc;
4use alloc::{borrow::ToOwned, format, string::String};
5
6use crate::ColorError;
7
8#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
9pub struct Color {
10 pub alpha: u8,
11 pub blue: u8,
12 pub green: u8,
13 pub red: u8,
14}
15
16impl Color {
17 pub fn from_rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
19 Color {
20 red,
21 green,
22 blue,
23 alpha,
24 }
25 }
26
27 pub fn from_rgb(red: u8, green: u8, blue: u8) -> Self {
29 Color {
30 red,
31 green,
32 blue,
33 alpha: 255,
34 }
35 }
36
37 pub fn from_hex(hex: &str) -> Result<Self, ColorError> {
40 if hex.len() == 0 {
41 return Err(ColorError::EmptyHexString());
42 }
43
44 let trimmed_hex = hex.trim_start_matches('#');
45
46 match trimmed_hex.len() {
47 0 => return Err(ColorError::EmptyTrimmedHexString()),
48 3 => {
49 let red = u8::from_str_radix(&trimmed_hex[0..1], 16).map_err(|_| {
50 ColorError::InvalidHexStringValue(
51 format!("#{}", trimmed_hex),
52 trimmed_hex[0..1].to_owned(),
53 )
54 })? * 17; let green = u8::from_str_radix(&trimmed_hex[1..2], 16).map_err(|_| {
56 ColorError::InvalidHexStringValue(
57 format!("#{}", trimmed_hex),
58 trimmed_hex[1..2].to_owned(),
59 )
60 })? * 17;
61 let blue = u8::from_str_radix(&trimmed_hex[2..3], 16).map_err(|_| {
62 ColorError::InvalidHexStringValue(
63 format!("#{}", trimmed_hex),
64 trimmed_hex[2..3].to_owned(),
65 )
66 })? * 17;
67 Ok(Color {
68 red,
69 green,
70 blue,
71 alpha: 255,
72 })
73 }
74 4 => {
75 let red = u8::from_str_radix(&trimmed_hex[0..1], 16).map_err(|_| {
76 ColorError::InvalidHexStringValue(
77 format!("#{}", trimmed_hex),
78 trimmed_hex[0..1].to_owned(),
79 )
80 })? * 17;
81 let green = u8::from_str_radix(&trimmed_hex[1..2], 16).map_err(|_| {
82 ColorError::InvalidHexStringValue(
83 format!("#{}", trimmed_hex),
84 trimmed_hex[1..2].to_owned(),
85 )
86 })? * 17;
87 let blue = u8::from_str_radix(&trimmed_hex[2..3], 16).map_err(|_| {
88 ColorError::InvalidHexStringValue(
89 format!("#{}", trimmed_hex),
90 trimmed_hex[2..3].to_owned(),
91 )
92 })? * 17;
93 let alpha = u8::from_str_radix(&trimmed_hex[3..4], 16).map_err(|_| {
94 ColorError::InvalidHexStringValue(
95 format!("#{}", trimmed_hex),
96 trimmed_hex[3..4].to_owned(),
97 )
98 })? * 17;
99 Ok(Color {
100 red,
101 green,
102 blue,
103 alpha,
104 })
105 }
106 6 => {
107 let red = u8::from_str_radix(&trimmed_hex[0..2], 16).map_err(|_| {
108 ColorError::InvalidHexStringValue(
109 format!("#{}", trimmed_hex),
110 trimmed_hex[0..2].to_owned(),
111 )
112 })?;
113 let green = u8::from_str_radix(&trimmed_hex[2..4], 16).map_err(|_| {
114 ColorError::InvalidHexStringValue(
115 format!("#{}", trimmed_hex),
116 trimmed_hex[2..4].to_owned(),
117 )
118 })?;
119 let blue = u8::from_str_radix(&trimmed_hex[4..6], 16).map_err(|_| {
120 ColorError::InvalidHexStringValue(
121 format!("#{}", trimmed_hex),
122 trimmed_hex[4..6].to_owned(),
123 )
124 })?;
125 Ok(Color {
126 red,
127 green,
128 blue,
129 alpha: 255,
130 })
131 }
132 8 => {
133 let red = u8::from_str_radix(&trimmed_hex[0..2], 16).map_err(|_| {
134 ColorError::InvalidHexStringValue(
135 format!("#{}", trimmed_hex),
136 trimmed_hex[0..2].to_owned(),
137 )
138 })?;
139 let green = u8::from_str_radix(&trimmed_hex[2..4], 16).map_err(|_| {
140 ColorError::InvalidHexStringValue(
141 format!("#{}", trimmed_hex),
142 trimmed_hex[2..4].to_owned(),
143 )
144 })?;
145 let blue = u8::from_str_radix(&trimmed_hex[4..6], 16).map_err(|_| {
146 ColorError::InvalidHexStringValue(
147 format!("#{}", trimmed_hex),
148 trimmed_hex[4..6].to_owned(),
149 )
150 })?;
151 let alpha = u8::from_str_radix(&trimmed_hex[6..8], 16).map_err(|_| {
152 ColorError::InvalidHexStringValue(
153 format!("#{}", trimmed_hex),
154 trimmed_hex[6..8].to_owned(),
155 )
156 })?;
157 Ok(Color {
158 red,
159 green,
160 blue,
161 alpha,
162 })
163 }
164 _ => Err(ColorError::InvalidHexStringLength(
165 trimmed_hex.to_owned(),
166 trimmed_hex.len(),
167 )),
168 }
169 }
170
171 pub fn to_hex(&self) -> String {
173 format!(
174 "#{:02X}{:02X}{:02X}{:02X}",
175 self.red, self.green, self.blue, self.alpha
176 )
177 }
178}
179
180impl Color {
182 pub const RED: Self = Color {
183 red: 255,
184 green: 0,
185 blue: 0,
186 alpha: 255,
187 };
188 pub const GREEN: Self = Color {
189 red: 0,
190 green: 255,
191 blue: 0,
192 alpha: 255,
193 };
194 pub const BLUE: Self = Color {
195 red: 0,
196 green: 0,
197 blue: 255,
198 alpha: 255,
199 };
200 pub const WHITE: Self = Color {
201 red: 255,
202 green: 255,
203 blue: 255,
204 alpha: 255,
205 };
206 pub const BLACK: Self = Color {
207 red: 0,
208 green: 0,
209 blue: 0,
210 alpha: 255,
211 };
212}
213
214#[cfg(feature = "std")]
215impl std::fmt::Display for Color {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 write!(
218 f,
219 "rgba({}, {}, {}, {})",
220 self.red, self.green, self.blue, self.alpha
221 )
222 }
223}
224
225impl From<(u8, u8, u8)> for Color {
226 fn from(rgb: (u8, u8, u8)) -> Self {
227 Color::from_rgb(rgb.0, rgb.1, rgb.2)
228 }
229}
230
231impl From<(u8, u8, u8, u8)> for Color {
232 fn from(rgba: (u8, u8, u8, u8)) -> Self {
233 Color::from_rgba(rgba.0, rgba.1, rgba.2, rgba.3)
234 }
235}
236
237impl From<&str> for Color {
238 fn from(hex: &str) -> Self {
239 Color::from_hex(hex).unwrap_or_default()
240 }
241}
242
243impl From<u32> for Color {
244 fn from(hex: u32) -> Self {
245 let red = ((hex >> 24) & 0xFF) as u8;
246 let green = ((hex >> 16) & 0xFF) as u8;
247 let blue = ((hex >> 8) & 0xFF) as u8;
248 let alpha = (hex & 0xFF) as u8;
249 Color {
250 red,
251 green,
252 blue,
253 alpha,
254 }
255 }
256}