#![allow(clippy::excessive_precision)]
use crate::ColorModel;
use crate::chan::{Ch8, Ch16, Ch32, Channel, Linear, Premultiplied, Straight};
use crate::el::{Pix, PixRgba, Pixel};
use std::ops::Range;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Oklab {}
impl Oklab {
pub fn l<P>(p: P) -> P::Chan
where
P: Pixel<Model = Self>,
{
p.get::<0>()
}
pub fn l_mut<P>(p: &mut P) -> &mut P::Chan
where
P: Pixel<Model = Self>,
{
p.get_mut::<0>()
}
pub fn a<P>(p: P) -> P::Chan
where
P: Pixel<Model = Self>,
{
p.get::<1>()
}
pub fn a_mut<P>(p: &mut P) -> &mut P::Chan
where
P: Pixel<Model = Self>,
{
p.get_mut::<1>()
}
pub fn b<P>(p: P) -> P::Chan
where
P: Pixel<Model = Self>,
{
p.get::<2>()
}
pub fn b_mut<P>(p: &mut P) -> &mut P::Chan
where
P: Pixel<Model = Self>,
{
p.get_mut::<2>()
}
}
impl ColorModel for Oklab {
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 pl = Self::l(p).to_f32();
let pa = Self::a(p).to_f32();
let pb = Self::b(p).to_f32();
let l_ = pl + 0.3963377774 * pa + 0.2158037573 * pb;
let m_ = pl - 0.1055613458 * pa - 0.0638541728 * pb;
let s_ = pl - 0.0894841775 * pa - 1.2914855480 * pb;
let l = l_ * l_ * l_;
let m = m_ * m_ * m_;
let s = s_ * s_ * s_;
let red = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
let green = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
let blue = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s;
PixRgba::<P>::new(red, green, blue, p.alpha().to_f32())
}
fn from_rgba<P>(rgba: PixRgba<P>) -> P
where
P: Pixel<Model = Self>,
{
let chan = rgba.channels();
let red = chan[0].to_f32();
let green = chan[1].to_f32();
let blue = chan[2].to_f32();
let alpha = chan[3];
let l = 0.4122214708 * red + 0.5363325363 * green + 0.0514459929 * blue;
let m = 0.2119034982 * red + 0.6806995451 * green + 0.1073969566 * blue;
let s = 0.0883024619 * red + 0.2817188376 * green + 0.6299787005 * blue;
let l_ = l.cbrt();
let m_ = m.cbrt();
let s_ = s.cbrt();
let pl = 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_;
let pa = 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_;
let pb = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_;
P::from_channels(&[pl.into(), pa.into(), pb.into(), alpha])
}
}
pub type Oklab8 = Pix<3, Ch8, Oklab, Straight, Linear>;
pub type Oklab16 = Pix<3, Ch16, Oklab, Straight, Linear>;
pub type Oklab32 = Pix<3, Ch32, Oklab, Straight, Linear>;
pub type Oklaba8 = Pix<4, Ch8, Oklab, Straight, Linear>;
pub type Oklaba16 = Pix<4, Ch16, Oklab, Straight, Linear>;
pub type Oklaba32 = Pix<4, Ch32, Oklab, Straight, Linear>;
pub type Oklaba8p = Pix<4, Ch8, Oklab, Premultiplied, Linear>;
pub type Oklaba16p = Pix<4, Ch16, Oklab, Premultiplied, Linear>;
pub type Oklaba32p = Pix<4, Ch32, Oklab, Premultiplied, Linear>;
#[cfg(test)]
mod test {
#[test]
fn oklab_to_rgb() {
}
}