use crate::{
rgb::{HasBlue, HasGreen, HasRed},
space::{RgbChannelScale, Srgb, channel::Channel},
};
impl<C> From<C> for Srgb
where
C: RgbChannelScale,
<C as HasRed>::Component: Channel,
<C as HasGreen>::Component: Channel,
<C as HasBlue>::Component: Channel,
{
fn from(c: C) -> Self {
Self {
r: c.red().to_f32() / C::RED_MAX,
g: c.green().to_f32() / C::GREEN_MAX,
b: c.blue().to_f32() / C::BLUE_MAX,
}
}
}
#[cfg(test)]
mod tests {
use crate::{
rgb::{Abgr8888, Argb1555, Argb4444, Argb8888, Bgr888, Rgb565, Rgb888, RgbF32},
space::Srgb,
};
#[test]
fn rgb888_roundtrip() {
let pixel = Rgb888::from_rgb(200, 50, 100);
let srgb = Srgb::from(pixel);
let back = Rgb888::from(srgb);
assert_eq!(back, pixel);
}
#[test]
fn bgr888_roundtrip() {
let pixel = Bgr888::from_bgr(200, 50, 100);
let back = Bgr888::from(Srgb::from(pixel));
assert_eq!(back, pixel);
}
#[test]
fn abgr8888_roundtrip_previously_missing_direction() {
let srgb = Srgb::new(1.0, 0.2, 0.4);
let pixel: Abgr8888 = srgb.into();
let back: Srgb = pixel.into();
assert!((back.r - srgb.r).abs() < 0.01);
assert!((back.g - srgb.g).abs() < 0.01);
assert!((back.b - srgb.b).abs() < 0.01);
}
#[test]
fn argb8888_roundtrip_previously_missing_direction() {
let srgb = Srgb::new(0.1, 0.9, 0.3);
let pixel: Argb8888 = srgb.into();
let back: Srgb = pixel.into();
assert!((back.r - srgb.r).abs() < 0.01);
assert!((back.g - srgb.g).abs() < 0.01);
assert!((back.b - srgb.b).abs() < 0.01);
}
#[test]
fn rgb565_conversion_scales_by_bit_depth_not_255() {
let pixel = Rgb565::from_rgb(31, 63, 31);
let srgb = Srgb::from(pixel);
assert!((srgb.r - 1.0).abs() < 1e-5, "r={}", srgb.r);
assert!((srgb.g - 1.0).abs() < 1e-5, "g={}", srgb.g);
assert!((srgb.b - 1.0).abs() < 1e-5, "b={}", srgb.b);
}
#[test]
fn rgb565_roundtrip_previously_missing_entirely() {
let pixel = Rgb565::from_rgb(31, 40, 10);
let back = Rgb565::from(Srgb::from(pixel));
assert_eq!(back, pixel);
}
#[test]
fn argb1555_rgb_roundtrip_previously_missing_entirely() {
use crate::{
alpha::HasAlpha,
rgb::{HasBlue, HasGreen, HasRed},
};
let pixel = Argb1555::from_rgb(31, 31, 31);
let back = Argb1555::from(Srgb::from(pixel));
assert_eq!((back.red(), back.green(), back.blue()), (31, 31, 31));
assert_eq!(back.alpha(), 0);
}
#[test]
fn argb4444_rgb_roundtrip_previously_missing_entirely() {
use crate::{
alpha::HasAlpha,
rgb::{HasBlue, HasGreen, HasRed},
};
let pixel = Argb4444::from_argb(15, 15, 0, 15);
let back = Argb4444::from(Srgb::from(pixel));
assert_eq!((back.red(), back.green(), back.blue()), (15, 0, 15));
assert_eq!(back.alpha(), 0);
}
#[test]
fn rgb_f32_roundtrip_previously_missing_entirely() {
let pixel = RgbF32::from_rgb(0.25, 0.5, 0.75);
let srgb = Srgb::from(pixel);
assert!((srgb.r - 0.25).abs() < 1e-6);
assert!((srgb.g - 0.5).abs() < 1e-6);
assert!((srgb.b - 0.75).abs() < 1e-6);
}
#[test]
fn custom_rgb_u16_gets_conversion_for_free() {
use crate::rgb::Rgb;
let pixel: Rgb<u16> = Rgb::from_rgb(65_535, 0, 32_768);
let srgb = Srgb::from(pixel);
assert!((srgb.r - 1.0).abs() < 1e-4);
assert!(srgb.g.abs() < 1e-4);
assert!((srgb.b - 0.5).abs() < 1e-3);
}
}