1use core::marker::PhantomData;
7
8use crate::color::Color;
9use crate::encoding::Linear;
10use crate::fixed::Q4_28;
11use crate::space::ColorSpace;
12
13pub struct Matrix3<Src: ColorSpace, Dst: ColorSpace> {
15 coefs: [[Q4_28; 3]; 3],
16 _pd: PhantomData<fn() -> (Src, Dst)>,
17}
18
19impl<Src: ColorSpace, Dst: ColorSpace> Copy for Matrix3<Src, Dst> {}
20
21impl<Src: ColorSpace, Dst: ColorSpace> Clone for Matrix3<Src, Dst> {
22 fn clone(&self) -> Self {
23 *self
24 }
25}
26
27impl<Src: ColorSpace, Dst: ColorSpace> PartialEq for Matrix3<Src, Dst> {
28 fn eq(&self, other: &Self) -> bool {
29 self.coefs == other.coefs
30 }
31}
32
33impl<Src: ColorSpace, Dst: ColorSpace> Eq for Matrix3<Src, Dst> {}
34
35impl<Src: ColorSpace, Dst: ColorSpace> core::fmt::Debug for Matrix3<Src, Dst> {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 f.debug_struct("Matrix3")
38 .field("coefs", &self.coefs)
39 .finish()
40 }
41}
42
43impl<Src: ColorSpace, Dst: ColorSpace> Matrix3<Src, Dst> {
44 #[must_use]
46 pub const fn from_q428(coefs: [[Q4_28; 3]; 3]) -> Self {
47 Self {
48 coefs,
49 _pd: PhantomData,
50 }
51 }
52
53 #[must_use]
56 pub const fn apply(&self, color: Color<Src, Linear>) -> Color<Dst, Linear> {
57 let [row0, row1, row2] = self.coefs;
58 Color::new([
59 crate::arith::mul_acc3(row0, color.ch),
60 crate::arith::mul_acc3(row1, color.ch),
61 crate::arith::mul_acc3(row2, color.ch),
62 ])
63 }
64
65 #[cfg(feature = "f32")]
71 #[must_use]
72 pub fn apply_f32(&self, color: crate::ColorF32<Src, Linear>) -> crate::ColorF32<Dst, Linear> {
73 let [row0, row1, row2] = self.coefs;
74 crate::ColorF32::new([
75 crate::color_f32::apply_row_f32(row0, color.ch),
76 crate::color_f32::apply_row_f32(row1, color.ch),
77 crate::color_f32::apply_row_f32(row2, color.ch),
78 ])
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use crate::encoding::Linear;
86 use crate::fixed::Q0_16;
87 use crate::space::Srgb;
88
89 #[test]
90 fn identity_leaves_linear_color_unchanged() {
91 let one = Q4_28::ONE;
92 let zero = Q4_28::ZERO;
93 let m = Matrix3::<Srgb, Srgb>::from_q428([
94 [one, zero, zero],
95 [zero, one, zero],
96 [zero, zero, one],
97 ]);
98 let c = Color::<Srgb, Linear>::new(Q0_16::array_from_raw([12, 34, 56]));
99 assert_eq!(m.apply(c), c);
100 }
101}