color.rs

  1use std::{
  2    borrow::Cow,
  3    fmt,
  4    ops::{Deref, DerefMut},
  5};
  6
  7use crate::json::ToJson;
  8use pathfinder_color::{ColorF, ColorU};
  9use schemars::JsonSchema;
 10use serde::{
 11    de::{self, Unexpected},
 12    Deserialize, Deserializer,
 13};
 14use serde_json::json;
 15
 16#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, JsonSchema)]
 17#[repr(transparent)]
 18pub struct Color(#[schemars(with = "String")] ColorU);
 19
 20impl Color {
 21    pub fn transparent_black() -> Self {
 22        Self(ColorU::transparent_black())
 23    }
 24
 25    pub fn black() -> Self {
 26        Self(ColorU::black())
 27    }
 28
 29    pub fn white() -> Self {
 30        Self(ColorU::white())
 31    }
 32
 33    pub fn red() -> Self {
 34        Self(ColorU::from_u32(0xff0000ff))
 35    }
 36
 37    pub fn green() -> Self {
 38        Self(ColorU::from_u32(0x00ff00ff))
 39    }
 40
 41    pub fn blue() -> Self {
 42        Self(ColorU::from_u32(0x0000ffff))
 43    }
 44
 45    pub fn yellow() -> Self {
 46        Self(ColorU::from_u32(0xffff00ff))
 47    }
 48
 49    pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
 50        Self(ColorU::new(r, g, b, a))
 51    }
 52
 53    pub fn from_u32(rgba: u32) -> Self {
 54        Self(ColorU::from_u32(rgba))
 55    }
 56
 57    pub fn blend(source: Color, dest: Color) -> Color {
 58        // Skip blending if we don't need it.
 59        if source.a == 255 {
 60            return source;
 61        } else if source.a == 0 {
 62            return dest;
 63        }
 64
 65        let source = source.0.to_f32();
 66        let dest = dest.0.to_f32();
 67
 68        let a = source.a() + (dest.a() * (1. - source.a()));
 69        let r = ((source.r() * source.a()) + (dest.r() * dest.a() * (1. - source.a()))) / a;
 70        let g = ((source.g() * source.a()) + (dest.g() * dest.a() * (1. - source.a()))) / a;
 71        let b = ((source.b() * source.a()) + (dest.b() * dest.a() * (1. - source.a()))) / a;
 72
 73        Self(ColorF::new(r, g, b, a).to_u8())
 74    }
 75
 76    pub fn fade_out(&mut self, fade: f32) {
 77        let fade = fade.clamp(0., 1.);
 78        self.0.a = (self.0.a as f32 * (1. - fade)) as u8;
 79    }
 80}
 81
 82impl<'de> Deserialize<'de> for Color {
 83    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 84    where
 85        D: Deserializer<'de>,
 86    {
 87        let literal: Cow<str> = Deserialize::deserialize(deserializer)?;
 88        if let Some(digits) = literal.strip_prefix('#') {
 89            if let Ok(value) = u32::from_str_radix(digits, 16) {
 90                if digits.len() == 6 {
 91                    return Ok(Color::from_u32((value << 8) | 0xFF));
 92                } else if digits.len() == 8 {
 93                    return Ok(Color::from_u32(value));
 94                }
 95            }
 96        }
 97        Err(de::Error::invalid_value(
 98            Unexpected::Str(literal.as_ref()),
 99            &"#RRGGBB[AA]",
100        ))
101    }
102}
103
104impl ToJson for Color {
105    fn to_json(&self) -> serde_json::Value {
106        json!(format!(
107            "0x{:x}{:x}{:x}{:x}",
108            self.0.r, self.0.g, self.0.b, self.0.a
109        ))
110    }
111}
112
113impl Deref for Color {
114    type Target = ColorU;
115    fn deref(&self) -> &Self::Target {
116        &self.0
117    }
118}
119
120impl DerefMut for Color {
121    fn deref_mut(&mut self) -> &mut Self::Target {
122        &mut self.0
123    }
124}
125
126impl fmt::Debug for Color {
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        self.0.fmt(f)
129    }
130}