use crate::ColorModel;
use crate::chan::{Ch8, Ch16, Ch32, Linear, Premultiplied, Srgb, Straight};
use crate::el::{Pix, PixRgba, Pixel};
use std::ops::Range;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Rgb {}
impl Rgb {
pub fn red<P>(p: P) -> P::Chan
where
P: Pixel<Model = Self>,
{
p.get::<0>()
}
pub fn red_mut<P>(p: &mut P) -> &mut P::Chan
where
P: Pixel<Model = Self>,
{
p.get_mut::<0>()
}
pub fn green<P>(p: P) -> P::Chan
where
P: Pixel<Model = Self>,
{
p.get::<1>()
}
pub fn green_mut<P>(p: &mut P) -> &mut P::Chan
where
P: Pixel<Model = Self>,
{
p.get_mut::<1>()
}
pub fn blue<P>(p: P) -> P::Chan
where
P: Pixel<Model = Self>,
{
p.get::<2>()
}
pub fn blue_mut<P>(p: &mut P) -> &mut P::Chan
where
P: Pixel<Model = Self>,
{
p.get_mut::<2>()
}
pub fn difference<P>(p: P, rhs: P) -> P
where
P: Pixel<Model = Self>,
{
let red = if Self::red(p) > Self::red(rhs) {
Self::red(p) - Self::red(rhs)
} else {
Self::red(rhs) - Self::red(p)
};
let green = if Self::green(p) > Self::green(rhs) {
Self::green(p) - Self::green(rhs)
} else {
Self::green(rhs) - Self::green(p)
};
let blue = if Self::blue(p) > Self::blue(rhs) {
Self::blue(p) - Self::blue(rhs)
} else {
Self::blue(rhs) - Self::blue(p)
};
let alpha = if Pixel::alpha(p) > Pixel::alpha(rhs) {
Pixel::alpha(p) - Pixel::alpha(rhs)
} else {
Pixel::alpha(rhs) - Pixel::alpha(p)
};
P::from_channels(&[red, green, blue, alpha])
}
pub fn within_threshold<P>(p: P, rhs: P) -> bool
where
P: Pixel<Model = Self>,
{
Self::red(p) <= Self::red(rhs)
&& Self::green(p) <= Self::green(rhs)
&& Self::blue(p) <= Self::blue(rhs)
&& Pixel::alpha(p) <= Pixel::alpha(rhs)
}
}
impl ColorModel for Rgb {
const CIRCULAR: Range<usize> = 0..0;
const LINEAR: Range<usize> = 0..3;
const ALPHA: usize = 3;
fn into_rgba<P>(p: P) -> PixRgba<P>
where
P: Pixel<Model = Self>,
{
let red = Rgb::red(p);
let green = Rgb::green(p);
let blue = Rgb::blue(p);
PixRgba::<P>::new::<P::Chan>(red, green, blue, p.alpha())
}
fn from_rgba<P>(rgba: PixRgba<P>) -> P
where
P: Pixel<Model = Self>,
{
P::from_channels(rgba.channels())
}
}
pub type Rgb8 = Pix<3, Ch8, Rgb, Straight, Linear>;
pub type Rgb16 = Pix<3, Ch16, Rgb, Straight, Linear>;
pub type Rgb32 = Pix<3, Ch32, Rgb, Straight, Linear>;
pub type Rgba8 = Pix<4, Ch8, Rgb, Straight, Linear>;
pub type Rgba16 = Pix<4, Ch16, Rgb, Straight, Linear>;
pub type Rgba32 = Pix<4, Ch32, Rgb, Straight, Linear>;
pub type Rgba8p = Pix<4, Ch8, Rgb, Premultiplied, Linear>;
pub type Rgba16p = Pix<4, Ch16, Rgb, Premultiplied, Linear>;
pub type Rgba32p = Pix<4, Ch32, Rgb, Premultiplied, Linear>;
pub type SRgb8 = Pix<3, Ch8, Rgb, Straight, Srgb>;
pub type SRgb16 = Pix<3, Ch16, Rgb, Straight, Srgb>;
pub type SRgb32 = Pix<3, Ch32, Rgb, Straight, Srgb>;
pub type SRgba8 = Pix<4, Ch8, Rgb, Straight, Srgb>;
pub type SRgba16 = Pix<4, Ch16, Rgb, Straight, Srgb>;
pub type SRgba32 = Pix<4, Ch32, Rgb, Straight, Srgb>;
pub type SRgba8p = Pix<4, Ch8, Rgb, Premultiplied, Srgb>;
pub type SRgba16p = Pix<4, Ch16, Rgb, Premultiplied, Srgb>;
pub type SRgba32p = Pix<4, Ch32, Rgb, Premultiplied, Srgb>;
#[cfg(test)]
mod tests {
use crate::el::Pixel;
use crate::ops::SrcOver;
use crate::rgb::*;
#[test]
fn rgba8_transparent() {
let mut dst = Rgba8p::new(0, 0, 0, 0);
let src = Rgba8p::new(20, 40, 80, 160);
dst.composite_channels(&src, SrcOver);
assert_eq!(dst, src);
dst.composite_channels(&Rgba8p::new(0, 0, 0, 0), SrcOver);
assert_eq!(dst, src);
dst = Rgba8p::new(0xFF, 0xFF, 0xFF, 0x00);
dst.composite_channels(&Rgba8p::new(0, 0, 0, 0), SrcOver);
assert_eq!(dst, Rgba8p::new(0xFF, 0xFF, 0xFF, 0x00));
}
}