minetest_worldmapper/
color.rs

1use image::{Pixel, Rgba};
2use serde::de::{self, Unexpected, Visitor};
3use serde::{Deserialize, Deserializer};
4use std::fmt;
5
6#[derive(Clone, Copy, Debug)]
7pub struct Color(pub Rgba<u8>);
8
9impl Default for Color {
10    fn default() -> Self {
11        Color(Rgba([0, 0, 0, 0]))
12    }
13}
14
15impl Color {
16    pub fn alpha(&self) -> u8 {
17        self.0[3]
18    }
19
20    pub fn with_background(&self, other: &Color) -> Color {
21        if self.alpha() == 255 {
22            return *self;
23        } else if self.alpha() == 0 {
24            return *other;
25        }
26        let fore_alpha = self.alpha() as f32 / 255.0;
27        let back_alpha = 1.0 - fore_alpha;
28        let r = fore_alpha * (self.0[0] as f32) + back_alpha * (other.0[0] as f32);
29        let g = fore_alpha * (self.0[1] as f32) + back_alpha * (other.0[1] as f32);
30        let b = fore_alpha * (self.0[2] as f32) + back_alpha * (other.0[2] as f32);
31        let a = fore_alpha + back_alpha * (other.alpha() as f32 / 255.0);
32        Color(Rgba::from([r as u8, g as u8, b as u8, (255.0 * a) as u8]))
33    }
34
35    pub fn lighten_up(&mut self, by: u8) {
36        self.0.apply_without_alpha(|c| c.saturating_add(by))
37    }
38
39    pub fn darken(&mut self, by: u8) {
40        self.0.apply_without_alpha(|c| c.saturating_sub(by))
41    }
42}
43
44struct ColorVisitor;
45
46impl<'de> Visitor<'de> for ColorVisitor {
47    type Value = Color;
48
49    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
50        write!(
51            formatter,
52            "a hexadecimal color string in the format 'abcdef' (rgb) or 'abcdef01' (rgba)"
53        )
54    }
55
56    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
57    where
58        E: de::Error,
59    {
60        let valid = ((s.len() == 6) || (s.len() == 8)) && s.chars().all(|c| c.is_ascii_hexdigit());
61        if valid {
62            // We ruled out a ParseIntError above, so can call unwrap
63            let r = u8::from_str_radix(&s[0..2], 16).unwrap();
64            let g = u8::from_str_radix(&s[2..4], 16).unwrap();
65            let b = u8::from_str_radix(&s[4..6], 16).unwrap();
66            let alpha: String = s.chars().skip(6).take(2).collect();
67            // An error here can only mean there is no alpha provided, so we can discard the error
68            let a = u8::from_str_radix(&alpha, 16).unwrap_or(255);
69            Ok(Color(Rgba::from([r, g, b, a])))
70        } else {
71            Err(de::Error::invalid_value(Unexpected::Str(s), &self))
72        }
73    }
74}
75
76impl<'de> Deserialize<'de> for Color {
77    fn deserialize<D>(deserializer: D) -> Result<Color, D::Error>
78    where
79        D: Deserializer<'de>,
80    {
81        deserializer.deserialize_str(ColorVisitor)
82    }
83}