moxcms/conversions/katana/
pcs_stages.rs

1/*
2 * // Copyright (c) Radzivon Bartoshyk 6/2025. All rights reserved.
3 * //
4 * // Redistribution and use in source and binary forms, with or without modification,
5 * // are permitted provided that the following conditions are met:
6 * //
7 * // 1.  Redistributions of source code must retain the above copyright notice, this
8 * // list of conditions and the following disclaimer.
9 * //
10 * // 2.  Redistributions in binary form must reproduce the above copyright notice,
11 * // this list of conditions and the following disclaimer in the documentation
12 * // and/or other materials provided with the distribution.
13 * //
14 * // 3.  Neither the name of the copyright holder nor the names of its
15 * // contributors may be used to endorse or promote products derived from
16 * // this software without specific prior written permission.
17 * //
18 * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29use crate::conversions::katana::KatanaIntermediateStage;
30use crate::conversions::katana::stages::BlackholeIntermediateStage;
31use crate::mlaf::mlaf;
32use crate::{CmsError, ColorProfile, DataColorSpace, Matrix3f, ProfileVersion};
33use std::marker::PhantomData;
34
35pub(crate) struct KatanaMatrixStage {
36    pub(crate) matrices: Vec<Matrix3f>,
37}
38
39impl KatanaMatrixStage {
40    pub(crate) fn new(matrix: Matrix3f) -> Self {
41        Self {
42            matrices: vec![matrix],
43        }
44    }
45}
46
47pub(crate) type KatanaDefaultIntermediate = dyn KatanaIntermediateStage<f32> + Send + Sync;
48
49impl KatanaIntermediateStage<f32> for KatanaMatrixStage {
50    fn stage(&self, input: &mut Vec<f32>) -> Result<Vec<f32>, CmsError> {
51        if input.len() % 3 != 0 {
52            return Err(CmsError::LaneMultipleOfChannels);
53        }
54
55        for m in self.matrices.iter() {
56            for dst in input.chunks_exact_mut(3) {
57                let x = dst[0];
58                let y = dst[1];
59                let z = dst[2];
60                dst[0] = mlaf(mlaf(x * m.v[0][0], y, m.v[0][1]), z, m.v[0][2]);
61                dst[1] = mlaf(mlaf(x * m.v[1][0], y, m.v[1][1]), z, m.v[1][2]);
62                dst[2] = mlaf(mlaf(x * m.v[2][0], y, m.v[2][1]), z, m.v[2][2]);
63            }
64        }
65
66        Ok(std::mem::take(input))
67    }
68}
69
70pub(crate) fn katana_pcs_lab_v4_to_v2(profile: &ColorProfile) -> Box<KatanaDefaultIntermediate> {
71    if profile.pcs == DataColorSpace::Lab && profile.version_internal <= ProfileVersion::V4_0 {
72        let v_mat = vec![Matrix3f {
73            v: [
74                [65280.0 / 65535.0, 0., 0.],
75                [0., 65280.0 / 65535.0, 0.],
76                [0., 0., 65280.0 / 65535.0],
77            ],
78        }];
79        return Box::new(KatanaMatrixStage { matrices: v_mat });
80    }
81    Box::new(BlackholeIntermediateStage {
82        _phantom: PhantomData,
83    })
84}
85
86pub(crate) fn katana_pcs_lab_v2_to_v4(profile: &ColorProfile) -> Box<KatanaDefaultIntermediate> {
87    if profile.pcs == DataColorSpace::Lab && profile.version_internal <= ProfileVersion::V4_0 {
88        let v_mat = vec![Matrix3f {
89            v: [
90                [65535.0 / 65280.0, 0., 0.],
91                [0., 65535.0 / 65280.0, 0.],
92                [0., 0., 65535.0 / 65280.0],
93            ],
94        }];
95        return Box::new(KatanaMatrixStage { matrices: v_mat });
96    }
97    Box::new(BlackholeIntermediateStage {
98        _phantom: PhantomData,
99    })
100}