use core::marker::PhantomData;
use crate::color::Color;
use crate::encoding::Linear;
use crate::fixed::Q4_28;
use crate::space::ColorSpace;
pub struct Matrix3<Src: ColorSpace, Dst: ColorSpace> {
coefs: [[Q4_28; 3]; 3],
_pd: PhantomData<fn() -> (Src, Dst)>,
}
impl<Src: ColorSpace, Dst: ColorSpace> Copy for Matrix3<Src, Dst> {}
impl<Src: ColorSpace, Dst: ColorSpace> Clone for Matrix3<Src, Dst> {
fn clone(&self) -> Self {
*self
}
}
impl<Src: ColorSpace, Dst: ColorSpace> PartialEq for Matrix3<Src, Dst> {
fn eq(&self, other: &Self) -> bool {
self.coefs == other.coefs
}
}
impl<Src: ColorSpace, Dst: ColorSpace> Eq for Matrix3<Src, Dst> {}
impl<Src: ColorSpace, Dst: ColorSpace> core::fmt::Debug for Matrix3<Src, Dst> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Matrix3")
.field("coefs", &self.coefs)
.finish()
}
}
impl<Src: ColorSpace, Dst: ColorSpace> Matrix3<Src, Dst> {
#[must_use]
pub const fn from_q428(coefs: [[Q4_28; 3]; 3]) -> Self {
Self {
coefs,
_pd: PhantomData,
}
}
#[must_use]
pub const fn apply(&self, color: Color<Src, Linear>) -> Color<Dst, Linear> {
let [row0, row1, row2] = self.coefs;
Color::new([
crate::arith::mul_acc3(row0, color.ch),
crate::arith::mul_acc3(row1, color.ch),
crate::arith::mul_acc3(row2, color.ch),
])
}
#[cfg(feature = "f32")]
#[must_use]
pub fn apply_f32(&self, color: crate::ColorF32<Src, Linear>) -> crate::ColorF32<Dst, Linear> {
let [row0, row1, row2] = self.coefs;
crate::ColorF32::new([
crate::color_f32::apply_row_f32(row0, color.ch),
crate::color_f32::apply_row_f32(row1, color.ch),
crate::color_f32::apply_row_f32(row2, color.ch),
])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::encoding::Linear;
use crate::fixed::Q0_16;
use crate::space::Srgb;
#[test]
fn identity_leaves_linear_color_unchanged() {
let one = Q4_28::ONE;
let zero = Q4_28::ZERO;
let m = Matrix3::<Srgb, Srgb>::from_q428([
[one, zero, zero],
[zero, one, zero],
[zero, zero, one],
]);
let c = Color::<Srgb, Linear>::new(Q0_16::array_from_raw([12, 34, 56]));
assert_eq!(m.apply(c), c);
}
}