1use crate::pic_scale_error::PicScaleError;
31use crate::scaler::ScalingF32;
32use crate::support::check_image_size_overflow;
33use crate::{ImageStore, ImageStoreMut, ResamplingFunction, Scaler, Scaling, ThreadingPolicy};
34use colorutils_rs::{rgb_to_sigmoidal, rgba_to_sigmoidal, sigmoidal_to_rgb, sigmoidal_to_rgba};
35
36#[derive(Debug, Copy, Clone)]
37pub struct SigmoidalScaler {
39 pub(crate) scaler: Scaler,
40}
41
42impl SigmoidalScaler {
43 pub fn new(filter: ResamplingFunction) -> Self {
44 SigmoidalScaler {
45 scaler: Scaler::new(filter),
46 }
47 }
48}
49
50impl Scaling for SigmoidalScaler {
51 fn set_threading_policy(&mut self, threading_policy: ThreadingPolicy) {
52 self.scaler.set_threading_policy(threading_policy)
53 }
54
55 fn resize_plane<'a>(
56 &'a self,
57 _: &ImageStore<'a, u8, 1>,
58 _: &mut ImageStoreMut<'a, u8, 1>,
59 ) -> Result<(), PicScaleError> {
60 unimplemented!()
61 }
62
63 fn resize_cbcr8<'a>(
64 &'a self,
65 _: &ImageStore<'a, u8, 2>,
66 _: &mut ImageStoreMut<'a, u8, 2>,
67 ) -> Result<(), PicScaleError> {
68 unimplemented!()
69 }
70
71 fn resize_gray_alpha<'a>(
72 &'a self,
73 _: &ImageStore<'a, u8, 2>,
74 _: &mut ImageStoreMut<'a, u8, 2>,
75 _: bool,
76 ) -> Result<(), PicScaleError> {
77 unimplemented!()
78 }
79
80 fn resize_rgb<'a>(
81 &self,
82 store: &ImageStore<'a, u8, 3>,
83 into: &mut ImageStoreMut<'a, u8, 3>,
84 ) -> Result<(), PicScaleError> {
85 let new_size = into.get_size();
86 into.validate()?;
87 store.validate()?;
88 if store.width == 0 || store.height == 0 || new_size.width == 0 || new_size.height == 0 {
89 return Err(PicScaleError::ZeroImageDimensions);
90 }
91
92 if check_image_size_overflow(store.width, store.height, store.channels) {
93 return Err(PicScaleError::SourceImageIsTooLarge);
94 }
95
96 if check_image_size_overflow(new_size.width, new_size.height, store.channels) {
97 return Err(PicScaleError::DestinationImageIsTooLarge);
98 }
99
100 if store.width == new_size.width && store.height == new_size.height {
101 store.copied_to_mut(into);
102 return Ok(());
103 }
104
105 const CN: usize = 3;
106
107 let mut target_vertical = vec![f32::default(); store.width * store.height * CN];
108
109 let mut lab_store =
110 ImageStoreMut::<f32, CN>::from_slice(&mut target_vertical, store.width, store.height)?;
111 lab_store.bit_depth = into.bit_depth;
112
113 let lab_stride = lab_store.width as u32 * CN as u32 * size_of::<f32>() as u32;
114 rgb_to_sigmoidal(
115 store.buffer.as_ref(),
116 store.width as u32 * CN as u32,
117 lab_store.buffer.borrow_mut(),
118 lab_stride,
119 lab_store.width as u32,
120 lab_store.height as u32,
121 );
122
123 let new_immutable_store = ImageStore::<f32, CN> {
124 buffer: std::borrow::Cow::Owned(target_vertical),
125 channels: CN,
126 width: store.width,
127 height: store.height,
128 stride: store.width * CN,
129 bit_depth: into.bit_depth,
130 };
131
132 let mut new_store = ImageStoreMut::<f32, CN>::alloc(into.width, into.height);
133 self.scaler
134 .resize_rgb_f32(&new_immutable_store, &mut new_store)?;
135
136 let new_lab_stride = new_store.width as u32 * CN as u32 * size_of::<f32>() as u32;
137
138 sigmoidal_to_rgb(
139 new_store.buffer.borrow(),
140 new_lab_stride,
141 into.buffer.borrow_mut(),
142 into.width as u32 * CN as u32,
143 new_store.width as u32,
144 new_store.height as u32,
145 );
146 Ok(())
147 }
148
149 fn resize_rgba<'a>(
150 &'a self,
151 store: &ImageStore<'a, u8, 4>,
152 into: &mut ImageStoreMut<'a, u8, 4>,
153 premultiply_alpha: bool,
154 ) -> Result<(), PicScaleError> {
155 let new_size = into.get_size();
156 into.validate()?;
157 store.validate()?;
158 if store.width == 0 || store.height == 0 || new_size.width == 0 || new_size.height == 0 {
159 return Err(PicScaleError::ZeroImageDimensions);
160 }
161
162 if check_image_size_overflow(store.width, store.height, store.channels) {
163 return Err(PicScaleError::SourceImageIsTooLarge);
164 }
165
166 if check_image_size_overflow(new_size.width, new_size.height, store.channels) {
167 return Err(PicScaleError::DestinationImageIsTooLarge);
168 }
169
170 if store.width == new_size.width && store.height == new_size.height {
171 store.copied_to_mut(into);
172 return Ok(());
173 }
174
175 const CN: usize = 4;
176
177 let mut target_vertical = vec![f32::default(); store.width * store.height * CN];
178
179 let mut lab_store =
180 ImageStoreMut::<f32, CN>::from_slice(&mut target_vertical, store.width, store.height)?;
181 lab_store.bit_depth = into.bit_depth;
182
183 let lab_stride = lab_store.width as u32 * CN as u32 * size_of::<f32>() as u32;
184 rgba_to_sigmoidal(
185 store.buffer.as_ref(),
186 store.width as u32 * CN as u32,
187 lab_store.buffer.borrow_mut(),
188 lab_stride,
189 lab_store.width as u32,
190 lab_store.height as u32,
191 );
192
193 let new_immutable_store = ImageStore::<f32, CN> {
194 buffer: std::borrow::Cow::Owned(target_vertical),
195 channels: CN,
196 width: store.width,
197 height: store.height,
198 stride: store.width * CN,
199 bit_depth: into.bit_depth,
200 };
201
202 let mut new_store = ImageStoreMut::<f32, CN>::alloc(into.width, into.height);
203 self.scaler
204 .resize_rgba_f32(&new_immutable_store, &mut new_store, premultiply_alpha)?;
205
206 let new_lab_stride = new_store.width as u32 * CN as u32 * size_of::<f32>() as u32;
207
208 sigmoidal_to_rgba(
209 new_store.buffer.borrow(),
210 new_lab_stride,
211 into.buffer.borrow_mut(),
212 into.width as u32 * CN as u32,
213 new_store.width as u32,
214 new_store.height as u32,
215 );
216 Ok(())
217 }
218}