chromashift/
srgb.rs

1use crate::{LinearRgb, ToAlpha};
2use core::fmt;
3
4/// An RGB colour space with defined chromacities.
5/// The components are:
6/// - Red - a number between 0 and 255
7/// - Blue - a number between 0 and 255
8/// - Green - a number between 0 and 255
9/// - Alpha - a number between 0.0 and 100.0
10#[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 ToAlpha for Srgb {
25	fn to_alpha(&self) -> f32 {
26		self.alpha
27	}
28}
29
30impl fmt::Display for Srgb {
31	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32		let Self { red, green, blue, alpha } = self;
33		write!(f, "rgb({red} {green} {blue}")?;
34		if *alpha < 100.0 {
35			write!(f, " / {alpha}%")?;
36		}
37		write!(f, ")")
38	}
39}
40
41fn linear(c: f64) -> f64 {
42	if c > 0.04045 { ((c + 0.055) / 1.055).powf(2.4) } else { c / 12.92 }
43}
44
45fn gamma(u: f64) -> f64 {
46	if u <= 0.0031308 { u * 12.92 } else { 1.055 * u.powf(1.0 / 2.4) - 0.055 }
47}
48
49fn clamp01(value: f64) -> f64 {
50	value.clamp(0.0, 1.0)
51}
52
53impl From<Srgb> for LinearRgb {
54	fn from(value: Srgb) -> Self {
55		let Srgb { red, green, blue, alpha } = value;
56		LinearRgb::new(linear(red as f64 / 255.0), linear(green as f64 / 255.0), linear(blue as f64 / 255.0), alpha)
57	}
58}
59
60impl From<LinearRgb> for Srgb {
61	fn from(value: LinearRgb) -> Self {
62		let LinearRgb { red, green, blue, alpha } = value;
63		Srgb::new(
64			(gamma(clamp01(red)) * 255.0).round() as u8,
65			(gamma(clamp01(green)) * 255.0).round() as u8,
66			(gamma(clamp01(blue)) * 255.0).round() as u8,
67			alpha,
68		)
69	}
70}
71
72#[cfg(feature = "anstyle")]
73impl From<Srgb> for anstyle::RgbColor {
74	fn from(value: Srgb) -> Self {
75		anstyle::RgbColor(value.red, value.green, value.blue)
76	}
77}
78
79#[cfg(feature = "anstyle")]
80impl From<anstyle::RgbColor> for Srgb {
81	fn from(value: anstyle::RgbColor) -> Self {
82		Srgb::new(value.0, value.1, value.2, 100.0)
83	}
84}