pub trait SrgbColorSpace {
fn linear_to_nonlinear_srgb(self) -> Self;
fn nonlinear_to_linear_srgb(self) -> Self;
}
impl SrgbColorSpace for f32 {
fn linear_to_nonlinear_srgb(self) -> f32 {
if self <= 0.0 {
return self;
}
if self <= 0.0031308 {
self * 12.92 } else {
(1.055 * self.powf(1.0 / 2.4)) - 0.055 }
}
fn nonlinear_to_linear_srgb(self) -> f32 {
if self <= 0.0 {
return self;
}
if self <= 0.04045 {
self / 12.92 } else {
((self + 0.055) / 1.055).powf(2.4) }
}
}
#[test]
fn test_srgb_full_roundtrip() {
let u8max: f32 = u8::max_value() as f32;
for color in 0..u8::max_value() {
let color01 = color as f32 / u8max;
let color_roundtrip = color01
.linear_to_nonlinear_srgb()
.nonlinear_to_linear_srgb();
assert_eq!(
(color01 * u8max).round() as u8,
(color_roundtrip * u8max).round() as u8
);
}
}