1use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub};
2use libm::pow;
3use s2json::{GetM, MValue, MValueCompatible, ValuePrimitive, ValueType};
4use serde::{Deserialize, Serialize};
5
6use crate::parsers::Reader;
7
8const GAMMA: f64 = 2.2;
10
11pub fn gamma_to_linear(n: f64) -> f64 {
13 pow(n / 255., 1. / GAMMA)
14}
15
16pub fn linear_to_gamma(n: f64) -> f64 {
18 pow(n, GAMMA) * 255.
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, ValuePrimitive)]
48pub struct RGBA {
49 pub r: f64,
51 pub g: f64,
53 pub b: f64,
55 pub a: f64,
57}
58impl Default for RGBA {
59 fn default() -> Self {
60 Self { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }
61 }
62}
63impl RGBA {
64 pub fn new(r: f64, g: f64, b: f64, a: f64) -> Self {
66 Self { r, g, b, a }
67 }
68
69 pub fn from_gamma(r: f64, g: f64, b: f64, a: f64) -> Self {
71 Self::new(pow(r, 1. / GAMMA), pow(g, 1. / GAMMA), pow(b, 1. / GAMMA), a)
72 }
73
74 pub fn to_gamma(self) -> (f64, f64, f64, f64) {
76 (pow(self.r, GAMMA), pow(self.g, GAMMA), pow(self.b, GAMMA), self.a)
77 }
78
79 pub fn from_u8s(r: u8, g: u8, b: u8, a: u8) -> Self {
81 let max_u8 = u8::MAX as f64;
82 let r = (r as f64) / max_u8;
84 let g = (g as f64) / max_u8;
85 let b = (b as f64) / max_u8;
86 let a = (a as f64) / max_u8;
87 Self::from_gamma(r, g, b, a)
88 }
89
90 pub fn to_u8s(self) -> (u8, u8, u8, u8) {
92 let (r, g, b, a) = self.to_gamma();
93 let max_u8 = u8::MAX as f64;
94 (
95 (r * max_u8).round() as u8,
96 (g * max_u8).round() as u8,
97 (b * max_u8).round() as u8,
98 (a * max_u8).round() as u8,
99 )
100 }
101
102 pub fn from_reader<R: Reader>(reader: &R, offset: Option<u64>) -> Self {
104 let offset = offset.unwrap_or(reader.tell());
105 let r = reader.uint16_le(Some(offset));
106 let g = reader.uint16_le(Some(offset + 2));
107 let b = reader.uint16_le(Some(offset + 4));
108 RGBA::from_u16s(r, g, b, u16::MAX)
109 }
110
111 pub fn from_u16s(r: u16, g: u16, b: u16, a: u16) -> Self {
113 let max_u16 = u16::MAX as f64;
114 let r = (r as f64) / max_u16;
115 let g = (g as f64) / max_u16;
116 let b = (b as f64) / max_u16;
117 let a = (a as f64) / max_u16;
118 Self::from_gamma(r, g, b, a)
119 }
120
121 pub fn to_u16s(&self) -> (u16, u16, u16, u16) {
123 let (r, g, b, a) = self.to_gamma();
124 let max_u16 = u16::MAX as f64;
125 (
126 (r * max_u16).round() as u16,
127 (g * max_u16).round() as u16,
128 (b * max_u16).round() as u16,
129 (a * max_u16).round() as u16,
130 )
131 }
132
133 pub fn from_u32(value: u32) -> Self {
135 let r = ((value >> 24) & 0xFF) as u8;
136 let g = ((value >> 16) & 0xFF) as u8;
137 let b = ((value >> 8) & 0xFF) as u8;
138 let a = (value & 0xFF) as u8;
139 Self::from_u8s(r, g, b, a)
140 }
141
142 pub fn to_u32s(&self) -> u32 {
145 let max_u8 = u8::MAX as f64;
146 let (r, g, b, a) = self.to_gamma();
147 ((r * max_u8).round() as u32) << 24
148 | ((g * max_u8).round() as u32) << 16
149 | ((b * max_u8).round() as u32) << 8
150 | ((a * max_u8).round() as u32)
151 }
152
153 pub fn from_u64(value: u64) -> Self {
155 let r = ((value >> 48) & 0xFFFF) as u16;
156 let g = ((value >> 32) & 0xFFFF) as u16;
157 let b = ((value >> 16) & 0xFFFF) as u16;
158 let a = (value & 0xFFFF) as u16;
159 Self::from_u16s(r, g, b, a)
160 }
161
162 pub fn to_u64s(&self) -> u64 {
164 let max_u16 = u16::MAX as f64;
165 let (r, g, b, a) = self.to_gamma();
166 ((r * max_u16).round() as u64) << 48
167 | ((g * max_u16).round() as u64) << 32
168 | ((b * max_u16).round() as u64) << 16
169 | ((a * max_u16).round() as u64)
170 }
171
172 pub fn from_hex(hex: &str) -> Self {
176 let hex = hex.trim_start_matches('#');
177 let len = hex.len();
178
179 let parse_byte = |i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap();
180
181 match len {
182 6 => {
183 let r = parse_byte(0);
184 let g = parse_byte(2);
185 let b = parse_byte(4);
186 Self::from_u8s(r, g, b, 255)
187 }
188 8 => {
189 let r = parse_byte(0);
190 let g = parse_byte(2);
191 let b = parse_byte(4);
192 let a = parse_byte(6);
193 Self::from_u8s(r, g, b, a)
194 }
195 _ => panic!("Invalid hex color: expected 6 or 8 hex digits, got {}", len),
196 }
197 }
198}
199impl GetM<RGBA> for RGBA {
200 fn m(&self) -> Option<&RGBA> {
201 Some(self)
202 }
203}
204impl Add<RGBA> for RGBA {
205 type Output = RGBA;
206 fn add(self, rhs: RGBA) -> Self::Output {
207 RGBA::new(self.r + rhs.r, self.g + rhs.g, self.b + rhs.b, self.a + rhs.a)
208 }
209}
210impl AddAssign<RGBA> for RGBA {
211 fn add_assign(&mut self, rhs: RGBA) {
212 self.r += rhs.r;
213 self.g += rhs.g;
214 self.b += rhs.b;
215 self.a += rhs.a;
216 }
217}
218impl AddAssign<f64> for RGBA {
219 fn add_assign(&mut self, rhs: f64) {
220 self.r += rhs;
221 self.g += rhs;
222 self.b += rhs;
223 self.a += rhs;
224 }
225}
226impl Sub<RGBA> for RGBA {
227 type Output = RGBA;
228 fn sub(self, rhs: RGBA) -> Self::Output {
229 RGBA::new(self.r - rhs.r, self.g - rhs.g, self.b - rhs.b, self.a - rhs.a)
230 }
231}
232impl Mul<RGBA> for RGBA {
233 type Output = RGBA;
234 fn mul(self, rhs: RGBA) -> Self::Output {
235 RGBA::new(self.r * rhs.r, self.g * rhs.g, self.b * rhs.b, self.a * rhs.a)
236 }
237}
238impl MulAssign<RGBA> for RGBA {
239 fn mul_assign(&mut self, rhs: RGBA) {
240 self.r *= rhs.r;
241 self.g *= rhs.g;
242 self.b *= rhs.b;
243 self.a *= rhs.a;
244 }
245}
246impl MulAssign<f64> for RGBA {
247 fn mul_assign(&mut self, rhs: f64) {
248 self.r *= rhs;
249 self.g *= rhs;
250 self.b *= rhs;
251 self.a *= rhs;
252 }
253}
254impl Div<RGBA> for RGBA {
255 type Output = RGBA;
256 fn div(self, rhs: RGBA) -> Self::Output {
257 RGBA::new(self.r / rhs.r, self.g / rhs.g, self.b / rhs.b, self.a / rhs.a)
258 }
259}
260impl DivAssign<RGBA> for RGBA {
261 fn div_assign(&mut self, rhs: RGBA) {
262 self.r /= rhs.r;
263 self.g /= rhs.g;
264 self.b /= rhs.b;
265 self.a /= rhs.a;
266 }
267}
268impl DivAssign<f64> for RGBA {
269 fn div_assign(&mut self, rhs: f64) {
270 self.r /= rhs;
271 self.g /= rhs;
272 self.b /= rhs;
273 self.a /= rhs;
274 }
275}
276impl PartialEq<f64> for RGBA {
277 fn eq(&self, rhs: &f64) -> bool {
278 self.r == *rhs || self.g == *rhs || self.b == *rhs || self.a == *rhs
279 }
280}
281impl MValueCompatible for RGBA {}
282impl From<MValue> for RGBA {
283 fn from(mvalue: MValue) -> Self {
284 let r = mvalue.get("r").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
285 let g = mvalue.get("g").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
286 let b = mvalue.get("b").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
287 let a = mvalue.get("a").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
288 RGBA::from_u8s(r, g, b, a)
289 }
290}
291impl From<&MValue> for RGBA {
292 fn from(mvalue: &MValue) -> Self {
293 let r = mvalue.get("r").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
294 let g = mvalue.get("g").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
295 let b = mvalue.get("b").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
296 let a = mvalue.get("a").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
297 RGBA::from_u8s(r, g, b, a)
298 }
299}
300impl From<RGBA> for MValue {
301 fn from(value: RGBA) -> Self {
302 let (r, g, b, a) = value.to_u8s();
303 MValue::from([
304 ("r".into(), (r as u64).into()),
305 ("g".into(), (g as u64).into()),
306 ("b".into(), (b as u64).into()),
307 ("a".into(), (a as u64).into()),
308 ])
309 }
310}
311impl From<RGBA> for ValueType {
312 fn from(value: RGBA) -> Self {
313 let (r, g, b, a) = value.to_u8s();
314 ValueType::Nested(MValue::from([
315 ("r".into(), (r as u64).into()),
316 ("g".into(), (g as u64).into()),
317 ("b".into(), (b as u64).into()),
318 ("a".into(), (a as u64).into()),
319 ]))
320 }
321}
322impl From<&ValueType> for RGBA {
323 fn from(value: &ValueType) -> Self {
324 let ValueType::Nested(mvalue) = value else {
325 panic!("Expected nested value type");
326 };
327 let r = mvalue.get("r").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
328 let g = mvalue.get("g").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
329 let b = mvalue.get("b").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
330 let a = mvalue.get("a").unwrap().to_prim().unwrap().to_u64().unwrap() as u8;
331 RGBA::from_u8s(r, g, b, a)
332 }
333}