1use serde::Deserialize;
9use serde::Serialize;
10use std::cmp::Ordering;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14pub struct Color {
15 pub r: u8,
16 pub g: u8,
17 pub b: u8,
18 pub a: u8,
19}
20
21pub const WHITE: Color = Color {
22 r: 255,
23 g: 255,
24 b: 255,
25 a: 255,
26};
27
28pub const BLACK: Color = Color {
29 r: 0,
30 g: 0,
31 b: 0,
32 a: 255,
33};
34
35pub const TRANSPARENT: Color = Color {
36 r: 0,
37 g: 0,
38 b: 0,
39 a: 0,
40};
41
42impl Color {
43 pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
44 Self { r, g, b, a }
45 }
46
47 pub(crate) fn from_ssa(mut color: &str) -> Result<Option<Self>, String> {
48 if !color.starts_with("&H") || color.len() != 10 {
49 if color.is_empty() {
50 return Ok(None);
51 }
52 return Err(format!("invalid color: #{color}"));
53 }
54 color = &color[2..];
55 Ok(Some(Self {
56 r: u8::from_str_radix(&color[6..8], 16).map_err(|e| e.to_string())?,
57 g: u8::from_str_radix(&color[4..6], 16).map_err(|e| e.to_string())?,
58 b: u8::from_str_radix(&color[2..4], 16).map_err(|e| e.to_string())?,
59 a: u8::from_str_radix(&color[0..2], 16).map_err(|e| e.to_string())?,
60 }))
61 }
62
63 pub(crate) fn from_vtt(color: &str) -> Result<Self, String> {
64 if let Some(color) = color.strip_prefix('#') {
65 let color = match color.len().cmp(&8) {
66 Ordering::Greater => return Err(format!("invalid hex color: #{color}")),
67 Ordering::Less if color.len() < 7 => format!("#{:0>6}FF", color),
68 Ordering::Less => format!("#{:F>8}", color),
69 _ => color.to_string(),
70 };
71 Ok(Self {
72 r: u8::from_str_radix(&color[0..2], 16).map_err(|e| e.to_string())?,
73 g: u8::from_str_radix(&color[2..4], 16).map_err(|e| e.to_string())?,
74 b: u8::from_str_radix(&color[4..6], 16).map_err(|e| e.to_string())?,
75 a: u8::from_str_radix(&color[6..8], 16).map_err(|e| e.to_string())?,
76 })
77 } else {
78 Ok(match color.to_lowercase().as_str() {
81 "aliceblue" => Self::new(240, 248, 255, 255),
82 "antiquewhite" => Self::new(250, 235, 215, 255),
83 "aqua" => Self::new(0, 255, 255, 255),
84 "aquamarine" => Self::new(127, 255, 212, 255),
85 "azure" => Self::new(240, 255, 255, 255),
86 "beige" => Self::new(245, 245, 220, 255),
87 "bisque" => Self::new(255, 228, 196, 255),
88 "black" => Self::new(0, 0, 0, 255),
89 "blanchedalmond" => Self::new(255, 235, 205, 255),
90 "blue" => Self::new(0, 0, 255, 255),
91 "blueviolet" => Self::new(138, 43, 226, 255),
92 "brown" => Self::new(165, 42, 42, 255),
93 "burlywood" => Self::new(222, 184, 135, 255),
94 "cadetblue" => Self::new(95, 158, 160, 255),
95 "chartreuse" => Self::new(127, 255, 0, 255),
96 "chocolate" => Self::new(210, 105, 30, 255),
97 "coral" => Self::new(255, 127, 80, 255),
98 "cornflowerblue" => Self::new(100, 149, 237, 255),
99 "cornsilk" => Self::new(255, 248, 220, 255),
100 "crimson" => Self::new(220, 20, 60, 255),
101 "cyan" => Self::new(0, 255, 255, 255),
102 "darkblue" => Self::new(0, 0, 139, 255),
103 "darkcyan" => Self::new(0, 139, 139, 255),
104 "darkgoldenrod" => Self::new(184, 134, 11, 255),
105 "darkgray" => Self::new(169, 169, 169, 255),
106 "darkgrey" => Self::new(169, 169, 169, 255),
107 "darkgreen" => Self::new(0, 100, 0, 255),
108 "darkkhaki" => Self::new(189, 183, 107, 255),
109 "darkmagenta" => Self::new(139, 0, 139, 255),
110 "darkolivegreen" => Self::new(85, 107, 47, 255),
111 "darkorange" => Self::new(255, 140, 0, 255),
112 "darkorchid" => Self::new(153, 50, 204, 255),
113 "darkred" => Self::new(139, 0, 0, 255),
114 "darksalmon" => Self::new(233, 150, 122, 255),
115 "darkseagreen" => Self::new(143, 188, 143, 255),
116 "darkslateblue" => Self::new(72, 61, 139, 255),
117 "darkslategray" => Self::new(47, 79, 79, 255),
118 "darkslategrey" => Self::new(47, 79, 79, 255),
119 "darkturquoise" => Self::new(0, 206, 209, 255),
120 "darkviolet" => Self::new(148, 0, 211, 255),
121 "deeppink" => Self::new(255, 20, 147, 255),
122 "deepskyblue" => Self::new(0, 191, 255, 255),
123 "dimgray" => Self::new(105, 105, 105, 255),
124 "dimgrey" => Self::new(105, 105, 105, 255),
125 "dodgerblue" => Self::new(30, 144, 255, 255),
126 "firebrick" => Self::new(178, 34, 34, 255),
127 "floralwhite" => Self::new(255, 250, 240, 255),
128 "forestgreen" => Self::new(34, 139, 34, 255),
129 "fuchsia" => Self::new(255, 0, 255, 255),
130 "gainsboro" => Self::new(220, 220, 220, 255),
131 "ghostwhite" => Self::new(248, 248, 255, 255),
132 "gold" => Self::new(255, 215, 0, 255),
133 "goldenrod" => Self::new(218, 165, 32, 255),
134 "gray" => Self::new(128, 128, 128, 255),
135 "grey" => Self::new(128, 128, 128, 255),
136 "green" => Self::new(0, 128, 0, 255),
137 "greenyellow" => Self::new(173, 255, 47, 255),
138 "honeydew" => Self::new(240, 255, 240, 255),
139 "hotpink" => Self::new(255, 105, 180, 255),
140 "ivory" => Self::new(255, 255, 240, 255),
141 "khaki" => Self::new(240, 230, 140, 255),
142 "lavender" => Self::new(230, 230, 250, 255),
143 "lavenderblush" => Self::new(255, 240, 245, 255),
144 "lawngreen" => Self::new(124, 252, 0, 255),
145 "lemonchiffon" => Self::new(255, 250, 205, 255),
146 "lightblue" => Self::new(173, 216, 230, 255),
147 "lightcoral" => Self::new(240, 128, 128, 255),
148 "lightcyan" => Self::new(224, 255, 255, 255),
149 "lightgoldenrodyellow" => Self::new(250, 250, 210, 255),
150 "lightgray" => Self::new(211, 211, 211, 255),
151 "lightgrey" => Self::new(211, 211, 211, 255),
152 "lightgreen" => Self::new(144, 238, 144, 255),
153 "lightpink" => Self::new(255, 182, 193, 255),
154 "lightsalmon" => Self::new(255, 160, 122, 255),
155 "lightseagreen" => Self::new(32, 178, 170, 255),
156 "lightskyblue" => Self::new(135, 206, 250, 255),
157 "lightslategray" => Self::new(119, 136, 153, 255),
158 "lightslategrey" => Self::new(119, 136, 153, 255),
159 "lightsteelblue" => Self::new(176, 196, 222, 255),
160 "lightyellow" => Self::new(255, 255, 224, 255),
161 "lime" => Self::new(0, 255, 0, 255),
162 "limegreen" => Self::new(50, 205, 50, 255),
163 "linen" => Self::new(250, 240, 230, 255),
164 "magenta" => Self::new(255, 0, 255, 255),
165 "maroon" => Self::new(128, 0, 0, 255),
166 "mediumaquamarine" => Self::new(102, 205, 170, 255),
167 "mediumblue" => Self::new(0, 0, 205, 255),
168 "mediumorchid" => Self::new(186, 85, 211, 255),
169 "mediumpurple" => Self::new(147, 112, 219, 255),
170 "mediumseagreen" => Self::new(60, 179, 113, 255),
171 "mediumslateblue" => Self::new(123, 104, 238, 255),
172 "mediumspringgreen" => Self::new(0, 250, 154, 255),
173 "mediumturquoise" => Self::new(72, 209, 204, 255),
174 "mediumvioletred" => Self::new(199, 21, 133, 255),
175 "midnightblue" => Self::new(25, 25, 112, 255),
176 "mintcream" => Self::new(245, 255, 250, 255),
177 "mistyrose" => Self::new(255, 228, 225, 255),
178 "moccasin" => Self::new(255, 228, 181, 255),
179 "navajowhite" => Self::new(255, 222, 173, 255),
180 "navy" => Self::new(0, 0, 128, 255),
181 "oldlace" => Self::new(253, 245, 230, 255),
182 "olive" => Self::new(128, 128, 0, 255),
183 "olivedrab" => Self::new(107, 142, 35, 255),
184 "orange" => Self::new(255, 165, 0, 255),
185 "orangered" => Self::new(255, 69, 0, 255),
186 "orchid" => Self::new(218, 112, 214, 255),
187 "palegoldenrod" => Self::new(238, 232, 170, 255),
188 "palegreen" => Self::new(152, 251, 152, 255),
189 "paleturquoise" => Self::new(175, 238, 238, 255),
190 "palevioletred" => Self::new(219, 112, 147, 255),
191 "papayawhip" => Self::new(255, 239, 213, 255),
192 "peachpuff" => Self::new(255, 218, 185, 255),
193 "peru" => Self::new(205, 133, 63, 255),
194 "pink" => Self::new(255, 192, 203, 255),
195 "plum" => Self::new(221, 160, 221, 255),
196 "powderblue" => Self::new(176, 224, 230, 255),
197 "purple" => Self::new(128, 0, 128, 255),
198 "rebeccapurple" => Self::new(102, 51, 153, 255),
199 "red" => Self::new(255, 0, 0, 255),
200 "rosybrown" => Self::new(188, 143, 143, 255),
201 "royalblue" => Self::new(65, 105, 225, 255),
202 "saddlebrown" => Self::new(139, 69, 19, 255),
203 "salmon" => Self::new(250, 128, 114, 255),
204 "sandybrown" => Self::new(244, 164, 96, 255),
205 "seagreen" => Self::new(46, 139, 87, 255),
206 "seashell" => Self::new(255, 245, 238, 255),
207 "sienna" => Self::new(160, 82, 45, 255),
208 "silver" => Self::new(192, 192, 192, 255),
209 "skyblue" => Self::new(135, 206, 235, 255),
210 "slateblue" => Self::new(106, 90, 205, 255),
211 "slategray" => Self::new(112, 128, 144, 255),
212 "slategrey" => Self::new(112, 128, 144, 255),
213 "snow" => Self::new(255, 250, 250, 255),
214 "springgreen" => Self::new(0, 255, 127, 255),
215 "steelblue" => Self::new(70, 130, 180, 255),
216 "tan" => Self::new(210, 180, 140, 255),
217 "teal" => Self::new(0, 128, 128, 255),
218 "thistle" => Self::new(216, 191, 216, 255),
219 "tomato" => Self::new(255, 99, 71, 255),
220 "turquoise" => Self::new(64, 224, 208, 255),
221 "violet" => Self::new(238, 130, 238, 255),
222 "wheat" => Self::new(245, 222, 179, 255),
223 "white" => Self::new(255, 255, 255, 255),
224 "whitesmoke" => Self::new(245, 245, 245, 255),
225 "yellow" => Self::new(255, 255, 0, 255),
226 "yellowgreen" => Self::new(154, 205, 50, 255),
227 _ => return Err(format!("unknown color name: {color}")),
228 })
229 }
230 }
231
232 pub fn to_ssa_string(&self) -> String {
233 if self.a == 255 {
234 format!("&H{:0>2X}{:0>2X}{:0>2X}", self.b, self.g, self.r)
235 } else {
236 format!(
237 "&H{:0>2X}{:0>2X}{:0>2X}{:0>2X}",
238 self.a, self.b, self.g, self.r
239 )
240 }
241 }
242
243 pub fn to_vtt_string(&self) -> String {
244 if self.a == 255 {
245 format!("#{:0>2X}{:0>2X}{:0>2X}", self.r, self.g, self.b)
246 } else {
247 format!(
248 "#{:0>2X}{:0>2X}{:0>2X}{:0>2X}",
249 self.r, self.g, self.b, self.a
250 )
251 }
252 }
253}
254
255#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
256pub enum Alignment {
257 BottomLeft = 1,
258 BottomCenter = 2,
259 BottomRight = 3,
260 MiddleLeft = 4,
261 MiddleCenter = 5,
262 MiddleRight = 6,
263 TopLeft = 7,
264 TopCenter = 8,
265 TopRight = 9,
266}
267
268impl Alignment {
269 pub fn infer_from_str(str: &str) -> Result<Self, &'static str> {
270 match str {
271 "1" => Ok(Alignment::BottomLeft),
272 "2" => Ok(Alignment::BottomCenter),
273 "3" => Ok(Alignment::BottomRight),
274 "4" => Ok(Alignment::MiddleLeft),
275 "5" => Ok(Alignment::MiddleCenter),
276 "6" => Ok(Alignment::MiddleRight),
277 "7" => Ok(Alignment::TopLeft),
278 "8" => Ok(Alignment::TopCenter),
279 "9" => Ok(Alignment::TopRight),
280 &_ => Err("ParseIntError"),
281 }
282 }
283}