Coverage Report

Created: 2025-10-10 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/moxcms-0.7.6/src/conversions/rgb2gray.rs
Line
Count
Source
1
/*
2
 * // Copyright (c) Radzivon Bartoshyk 2/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
 */
29
use crate::mlaf::mlaf;
30
use crate::transform::PointeeSizeExpressible;
31
use crate::{CmsError, Layout, TransformExecutor, Vector3f};
32
use num_traits::AsPrimitive;
33
34
#[derive(Clone)]
35
pub(crate) struct ToneReproductionRgbToGray<T, const BUCKET: usize> {
36
    pub(crate) r_linear: Box<[f32; BUCKET]>,
37
    pub(crate) g_linear: Box<[f32; BUCKET]>,
38
    pub(crate) b_linear: Box<[f32; BUCKET]>,
39
    pub(crate) gray_gamma: Box<[T; 65536]>,
40
}
41
42
#[derive(Clone)]
43
struct TransformRgbToGrayExecutor<
44
    T,
45
    const SRC_LAYOUT: u8,
46
    const DST_LAYOUT: u8,
47
    const BUCKET: usize,
48
> {
49
    trc_box: ToneReproductionRgbToGray<T, BUCKET>,
50
    weights: Vector3f,
51
    bit_depth: usize,
52
    gamma_lut: usize,
53
}
54
55
0
pub(crate) fn make_rgb_to_gray<
56
0
    T: Copy + Default + PointeeSizeExpressible + Send + Sync + 'static,
57
0
    const BUCKET: usize,
58
0
>(
59
0
    src_layout: Layout,
60
0
    dst_layout: Layout,
61
0
    trc: ToneReproductionRgbToGray<T, BUCKET>,
62
0
    weights: Vector3f,
63
0
    gamma_lut: usize,
64
0
    bit_depth: usize,
65
0
) -> Box<dyn TransformExecutor<T> + Send + Sync>
66
0
where
67
0
    u32: AsPrimitive<T>,
68
{
69
0
    match src_layout {
70
0
        Layout::Rgb => match dst_layout {
71
0
            Layout::Rgb => unreachable!(),
72
0
            Layout::Rgba => unreachable!(),
73
0
            Layout::Gray => Box::new(TransformRgbToGrayExecutor::<
74
0
                T,
75
0
                { Layout::Rgb as u8 },
76
0
                { Layout::Gray as u8 },
77
0
                BUCKET,
78
0
            > {
79
0
                trc_box: trc,
80
0
                weights,
81
0
                bit_depth,
82
0
                gamma_lut,
83
0
            }),
84
0
            Layout::GrayAlpha => Box::new(TransformRgbToGrayExecutor::<
85
0
                T,
86
0
                { Layout::Rgb as u8 },
87
0
                { Layout::GrayAlpha as u8 },
88
0
                BUCKET,
89
0
            > {
90
0
                trc_box: trc,
91
0
                weights,
92
0
                bit_depth,
93
0
                gamma_lut,
94
0
            }),
95
0
            _ => unreachable!(),
96
        },
97
0
        Layout::Rgba => match dst_layout {
98
0
            Layout::Rgb => unreachable!(),
99
0
            Layout::Rgba => unreachable!(),
100
0
            Layout::Gray => Box::new(TransformRgbToGrayExecutor::<
101
0
                T,
102
0
                { Layout::Rgba as u8 },
103
0
                { Layout::Gray as u8 },
104
0
                BUCKET,
105
0
            > {
106
0
                trc_box: trc,
107
0
                weights,
108
0
                bit_depth,
109
0
                gamma_lut,
110
0
            }),
111
0
            Layout::GrayAlpha => Box::new(TransformRgbToGrayExecutor::<
112
0
                T,
113
0
                { Layout::Rgba as u8 },
114
0
                { Layout::GrayAlpha as u8 },
115
0
                BUCKET,
116
0
            > {
117
0
                trc_box: trc,
118
0
                weights,
119
0
                bit_depth,
120
0
                gamma_lut,
121
0
            }),
122
0
            _ => unreachable!(),
123
        },
124
0
        Layout::Gray => unreachable!(),
125
0
        Layout::GrayAlpha => unreachable!(),
126
0
        _ => unreachable!(),
127
    }
128
0
}
Unexecuted instantiation: moxcms::conversions::rgb2gray::make_rgb_to_gray::<f64, 65536>
Unexecuted instantiation: moxcms::conversions::rgb2gray::make_rgb_to_gray::<f32, 65536>
Unexecuted instantiation: moxcms::conversions::rgb2gray::make_rgb_to_gray::<u8, 256>
Unexecuted instantiation: moxcms::conversions::rgb2gray::make_rgb_to_gray::<u16, 65536>
129
130
impl<
131
    T: Copy + Default + PointeeSizeExpressible + 'static,
132
    const SRC_LAYOUT: u8,
133
    const DST_LAYOUT: u8,
134
    const BUCKET: usize,
135
> TransformExecutor<T> for TransformRgbToGrayExecutor<T, SRC_LAYOUT, DST_LAYOUT, BUCKET>
136
where
137
    u32: AsPrimitive<T>,
138
{
139
0
    fn transform(&self, src: &[T], dst: &mut [T]) -> Result<(), CmsError> {
140
0
        let src_cn = Layout::from(SRC_LAYOUT);
141
0
        let dst_cn = Layout::from(DST_LAYOUT);
142
0
        let src_channels = src_cn.channels();
143
0
        let dst_channels = dst_cn.channels();
144
145
0
        if src.len() / src_channels != dst.len() / dst_channels {
146
0
            return Err(CmsError::LaneSizeMismatch);
147
0
        }
148
0
        if src.len() % src_channels != 0 {
149
0
            return Err(CmsError::LaneMultipleOfChannels);
150
0
        }
151
0
        if dst.len() % dst_channels != 0 {
152
0
            return Err(CmsError::LaneMultipleOfChannels);
153
0
        }
154
155
0
        let scale_value = (self.gamma_lut - 1) as f32;
156
0
        let max_value = ((1u32 << self.bit_depth) - 1).as_();
157
158
0
        for (src, dst) in src
159
0
            .chunks_exact(src_channels)
160
0
            .zip(dst.chunks_exact_mut(dst_channels))
161
        {
162
0
            let r = self.trc_box.r_linear[src[src_cn.r_i()]._as_usize()];
163
0
            let g = self.trc_box.g_linear[src[src_cn.g_i()]._as_usize()];
164
0
            let b = self.trc_box.b_linear[src[src_cn.b_i()]._as_usize()];
165
0
            let a = if src_channels == 4 {
166
0
                src[src_cn.a_i()]
167
            } else {
168
0
                max_value
169
            };
170
0
            let grey = mlaf(
171
                0.5,
172
0
                mlaf(
173
0
                    mlaf(self.weights.v[0] * r, self.weights.v[1], g),
174
0
                    self.weights.v[2],
175
0
                    b,
176
                )
177
0
                .min(1.)
178
0
                .max(0.),
179
0
                scale_value,
180
            );
181
0
            dst[0] = self.trc_box.gray_gamma[(grey as u16) as usize];
182
0
            if dst_channels == 2 {
183
0
                dst[1] = a;
184
0
            }
185
        }
186
187
0
        Ok(())
188
0
    }
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<f64, 0, 2, 65536> as moxcms::transform::TransformExecutor<f64>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<f64, 0, 3, 65536> as moxcms::transform::TransformExecutor<f64>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<f64, 1, 2, 65536> as moxcms::transform::TransformExecutor<f64>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<f64, 1, 3, 65536> as moxcms::transform::TransformExecutor<f64>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<f32, 0, 2, 65536> as moxcms::transform::TransformExecutor<f32>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<f32, 0, 3, 65536> as moxcms::transform::TransformExecutor<f32>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<f32, 1, 2, 65536> as moxcms::transform::TransformExecutor<f32>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<f32, 1, 3, 65536> as moxcms::transform::TransformExecutor<f32>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<u8, 0, 2, 256> as moxcms::transform::TransformExecutor<u8>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<u8, 0, 3, 256> as moxcms::transform::TransformExecutor<u8>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<u8, 1, 2, 256> as moxcms::transform::TransformExecutor<u8>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<u8, 1, 3, 256> as moxcms::transform::TransformExecutor<u8>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<u16, 0, 2, 65536> as moxcms::transform::TransformExecutor<u16>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<u16, 0, 3, 65536> as moxcms::transform::TransformExecutor<u16>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<u16, 1, 2, 65536> as moxcms::transform::TransformExecutor<u16>>::transform
Unexecuted instantiation: <moxcms::conversions::rgb2gray::TransformRgbToGrayExecutor<u16, 1, 3, 65536> as moxcms::transform::TransformExecutor<u16>>::transform
189
}