use crate::ColorModel;
use crate::chan::{
Ch8, Ch16, Ch32, Channel, Linear, Premultiplied, Srgb, Straight,
};
use crate::el::{Pix, PixRgba, Pixel};
use std::ops::Range;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Gray {}
impl Gray {
pub fn value<P>(p: P) -> P::Chan
where
P: Pixel<Model = Self>,
{
p.get::<0>()
}
pub fn value_mut<P>(p: &mut P) -> &mut P::Chan
where
P: Pixel<Model = Self>,
{
p.get_mut::<0>()
}
}
impl ColorModel for Gray {
const CIRCULAR: Range<usize> = 0..0;
const LINEAR: Range<usize> = 0..1;
const ALPHA: usize = 1;
fn into_rgba<P>(p: P) -> PixRgba<P>
where
P: Pixel<Model = Self>,
{
let value = Self::value(p);
PixRgba::<P>::new::<P::Chan>(value, value, value, p.alpha())
}
fn from_rgba<P>(rgba: PixRgba<P>) -> P
where
P: Pixel<Model = Self>,
{
const RED_COEF: f32 = 0.212_6;
const GREEN_COEF: f32 = 0.715_2;
const BLUE_COEF: f32 = 0.072_2;
let chan = rgba.channels();
let red = chan[0].to_f32() * RED_COEF;
let green = chan[1].to_f32() * GREEN_COEF;
let blue = chan[2].to_f32() * BLUE_COEF;
let value = P::Chan::from(red + green + blue);
let alpha = chan[3];
P::from_channels(&[value, alpha])
}
}
pub type Gray8 = Pix<1, Ch8, Gray, Straight, Linear>;
pub type Gray16 = Pix<1, Ch16, Gray, Straight, Linear>;
pub type Gray32 = Pix<1, Ch32, Gray, Straight, Linear>;
pub type Graya8 = Pix<2, Ch8, Gray, Straight, Linear>;
pub type Graya16 = Pix<2, Ch16, Gray, Straight, Linear>;
pub type Graya32 = Pix<2, Ch32, Gray, Straight, Linear>;
pub type Graya8p = Pix<2, Ch8, Gray, Premultiplied, Linear>;
pub type Graya16p = Pix<2, Ch16, Gray, Premultiplied, Linear>;
pub type Graya32p = Pix<2, Ch32, Gray, Premultiplied, Linear>;
pub type SGray8 = Pix<1, Ch8, Gray, Straight, Srgb>;
pub type SGray16 = Pix<1, Ch16, Gray, Straight, Srgb>;
pub type SGray32 = Pix<1, Ch32, Gray, Straight, Srgb>;
pub type SGraya8 = Pix<2, Ch8, Gray, Straight, Srgb>;
pub type SGraya16 = Pix<2, Ch16, Gray, Straight, Srgb>;
pub type SGraya32 = Pix<2, Ch32, Gray, Straight, Srgb>;
pub type SGraya8p = Pix<2, Ch8, Gray, Premultiplied, Srgb>;
pub type SGraya16p = Pix<2, Ch16, Gray, Premultiplied, Srgb>;
pub type SGraya32p = Pix<2, Ch32, Gray, Premultiplied, Srgb>;
#[cfg(test)]
mod test {
use crate::el::Pixel;
use crate::gray::*;
use crate::matte::*;
use crate::rgb::*;
#[test]
fn rgb_to_gray() {
assert_eq!(
SGray8::new(0x7B),
SRgb16::new(0x4321, 0x9085, 0x5543).convert(),
);
assert_eq!(
SGray8::new(0x46),
SRgb16::new(0x5768, 0x4091, 0x5000).convert(),
);
}
#[test]
fn gray_to_rgb() {
assert_eq!(SRgb8::new(0x45, 0x45, 0x45), SGray8::new(0x45).convert());
assert_eq!(
SRgb8::new(0xDA, 0xDA, 0xDA),
SGraya8::new(0xDA, 0x33).convert(),
);
assert_eq!(SRgb8::new(0xBA, 0xBA, 0xBA), Gray8::new(0x7D).convert());
}
#[test]
fn matte_to_gray() {
assert_eq!(SGraya8::new(0xFF, 0xAB), Matte16::new(0xABCD).convert());
assert_eq!(SGraya8::new(0xFF, 0x98), Matte16::new(0x9876).convert());
}
#[test]
fn gray_to_matte() {
assert_eq!(Matte16::new(0x9494), SGraya8::new(0x67, 0x94).convert());
assert_eq!(Matte16::new(0xA2A2), SGraya8::new(0xBA, 0xA2).convert());
assert_eq!(Matte8::new(0x80), SGraya32::new(0.75, 0.5).convert());
}
}