1use crate::LinearRgb;
2use core::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct Srgb {
12 pub red: u8,
13 pub green: u8,
14 pub blue: u8,
15 pub alpha: f32,
16}
17
18impl Srgb {
19 pub fn new(red: u8, green: u8, blue: u8, alpha: f32) -> Self {
20 Self { red, green, blue, alpha: alpha.clamp(0.0, 100.0) }
21 }
22}
23
24impl fmt::Display for Srgb {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 let Self { red, green, blue, alpha } = self;
27 write!(f, "rgb({red} {green} {blue}")?;
28 if *alpha < 100.0 {
29 write!(f, " / {alpha}%")?;
30 }
31 write!(f, ")")
32 }
33}
34
35fn linear(c: f64) -> f64 {
36 if c > 0.04045 { ((c + 0.055) / 1.055).powf(2.4) } else { c / 12.92 }
37}
38
39fn gamma(u: f64) -> f64 {
40 if u <= 0.0031308 { u * 12.92 } else { 1.055 * u.powf(1.0 / 2.4) - 0.055 }
41}
42
43fn clamp01(value: f64) -> f64 {
44 value.clamp(0.0, 1.0)
45}
46
47impl From<Srgb> for LinearRgb {
48 fn from(value: Srgb) -> Self {
49 let Srgb { red, green, blue, alpha } = value;
50 LinearRgb::new(linear(red as f64 / 255.0), linear(green as f64 / 255.0), linear(blue as f64 / 255.0), alpha)
51 }
52}
53
54impl From<LinearRgb> for Srgb {
55 fn from(value: LinearRgb) -> Self {
56 let LinearRgb { red, green, blue, alpha } = value;
57 Srgb::new(
58 (gamma(clamp01(red)) * 255.0).round() as u8,
59 (gamma(clamp01(green)) * 255.0).round() as u8,
60 (gamma(clamp01(blue)) * 255.0).round() as u8,
61 alpha,
62 )
63 }
64}
65
66#[cfg(feature = "anstyle")]
67impl From<Srgb> for anstyle::RgbColor {
68 fn from(value: Srgb) -> Self {
69 anstyle::RgbColor(value.red, value.green, value.blue)
70 }
71}
72
73#[cfg(feature = "anstyle")]
74impl From<anstyle::RgbColor> for Srgb {
75 fn from(value: anstyle::RgbColor) -> Self {
76 Srgb::new(value.0, value.1, value.2, 100.0)
77 }
78}