Skip to main content

pic_scale/colors/
luv_scaler.rs

1/*
2 * Copyright (c) Radzivon Bartoshyk. 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 colorutils_rs::{
30    SRGB_TO_XYZ_D65, TransferFunction, XYZ_TO_SRGB_D65, luv_to_rgb, luv_with_alpha_to_rgba,
31    rgb_to_luv, rgba_to_luv_with_alpha,
32};
33use std::sync::Arc;
34
35use crate::colors::common_splitter::{SplitPlanInterceptor, Splitter};
36use crate::plan::Resampling;
37use crate::validation::PicScaleError;
38use crate::{ImageSize, ImageStore, ImageStoreMut, ResamplingFunction, Scaler, ThreadingPolicy};
39
40#[derive(Debug, Copy, Clone)]
41/// Converts image to *CIE LUV* components scales it and convert back
42pub struct LuvScaler {
43    pub(crate) scaler: Scaler,
44}
45
46impl LuvScaler {
47    pub fn new(filter: ResamplingFunction) -> Self {
48        LuvScaler {
49            scaler: Scaler::new(filter),
50        }
51    }
52}
53
54struct LuvRgbSplitter {}
55
56impl Splitter<u8, f32, 3> for LuvRgbSplitter {
57    fn split(
58        &self,
59        from: &ImageStore<'_, u8, 3>,
60        into: &mut ImageStoreMut<'_, f32, 3>,
61    ) -> Result<(), PicScaleError> {
62        let mut dst_buffer = into.to_colorutils_buffer_mut();
63        rgb_to_luv(
64            &from.to_colorutils_buffer(),
65            &mut dst_buffer,
66            &SRGB_TO_XYZ_D65,
67            TransferFunction::Srgb,
68        )
69        .map_err(|x| PicScaleError::Generic(x.to_string()))
70    }
71
72    fn merge(
73        &self,
74        from: &ImageStore<'_, f32, 3>,
75        into: &mut ImageStoreMut<'_, u8, 3>,
76    ) -> Result<(), PicScaleError> {
77        let mut dst_buffer = into.to_colorutils_buffer_mut();
78        luv_to_rgb(
79            &from.to_colorutils_buffer(),
80            &mut dst_buffer,
81            &XYZ_TO_SRGB_D65,
82            TransferFunction::Srgb,
83        )
84        .map_err(|x| PicScaleError::Generic(x.to_string()))
85    }
86
87    fn bit_depth(&self) -> usize {
88        8
89    }
90}
91
92struct LuvRgbaSplitter {}
93
94impl Splitter<u8, f32, 4> for LuvRgbaSplitter {
95    fn split(
96        &self,
97        from: &ImageStore<'_, u8, 4>,
98        into: &mut ImageStoreMut<'_, f32, 4>,
99    ) -> Result<(), PicScaleError> {
100        let mut dst_buffer = into.to_colorutils_buffer_mut();
101
102        rgba_to_luv_with_alpha(
103            &from.to_colorutils_buffer(),
104            &mut dst_buffer,
105            &SRGB_TO_XYZ_D65,
106            TransferFunction::Srgb,
107        )
108        .map_err(|x| PicScaleError::Generic(x.to_string()))
109    }
110
111    fn merge(
112        &self,
113        from: &ImageStore<'_, f32, 4>,
114        into: &mut ImageStoreMut<'_, u8, 4>,
115    ) -> Result<(), PicScaleError> {
116        let mut dst_buffer = into.to_colorutils_buffer_mut();
117        luv_with_alpha_to_rgba(
118            &from.to_colorutils_buffer(),
119            &mut dst_buffer,
120            &XYZ_TO_SRGB_D65,
121            TransferFunction::Srgb,
122        )
123        .map_err(|x| PicScaleError::Generic(x.to_string()))
124    }
125
126    fn bit_depth(&self) -> usize {
127        8
128    }
129}
130
131impl LuvScaler {
132    pub fn set_threading_policy(&mut self, threading_policy: ThreadingPolicy) -> Self {
133        self.scaler.set_threading_policy(threading_policy);
134        *self
135    }
136
137    pub fn plan_rgb_resampling(
138        &self,
139        source_size: ImageSize,
140        target_size: ImageSize,
141    ) -> Result<Arc<Resampling<u8, 3>>, PicScaleError> {
142        let intercept = self
143            .scaler
144            .plan_rgb_resampling_f32(source_size, target_size)?;
145        let scratch_size = intercept.scratch_size();
146        Ok(Arc::new(SplitPlanInterceptor {
147            intercept,
148            splitter: Arc::new(LuvRgbSplitter {}),
149            inner_scratch: scratch_size,
150        }))
151    }
152
153    pub fn plan_rgba_resampling(
154        &self,
155        source_size: ImageSize,
156        target_size: ImageSize,
157        premultiply_alpha: bool,
158    ) -> Result<Arc<Resampling<u8, 4>>, PicScaleError> {
159        let intercept =
160            self.scaler
161                .plan_rgba_resampling_f32(source_size, target_size, premultiply_alpha)?;
162        let scratch_size = intercept.scratch_size();
163        Ok(Arc::new(SplitPlanInterceptor {
164            intercept,
165            splitter: Arc::new(LuvRgbaSplitter {}),
166            inner_scratch: scratch_size,
167        }))
168    }
169}