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_cbcr8<'a>(
56 &'a self,
57 _: &ImageStore<'a, u8, 2>,
58 _: &mut ImageStoreMut<'a, u8, 2>,
59 ) -> Result<(), PicScaleError> {
60 unimplemented!()
61 }
62
63 fn resize_rgb<'a>(
64 &self,
65 store: &ImageStore<'a, u8, 3>,
66 into: &mut ImageStoreMut<'a, u8, 3>,
67 ) -> Result<(), PicScaleError> {
68 let new_size = into.get_size();
69 into.validate()?;
70 store.validate()?;
71 if store.width == 0 || store.height == 0 || new_size.width == 0 || new_size.height == 0 {
72 return Err(PicScaleError::ZeroImageDimensions);
73 }
74
75 if check_image_size_overflow(store.width, store.height, store.channels) {
76 return Err(PicScaleError::SourceImageIsTooLarge);
77 }
78
79 if check_image_size_overflow(new_size.width, new_size.height, store.channels) {
80 return Err(PicScaleError::DestinationImageIsTooLarge);
81 }
82
83 if store.width == new_size.width && store.height == new_size.height {
84 store.copied_to_mut(into);
85 return Ok(());
86 }
87
88 const COMPONENTS: usize = 3;
89
90 let mut target_vertical = vec![f32::default(); store.width * store.height * COMPONENTS];
91
92 let mut lab_store = ImageStoreMut::<f32, COMPONENTS>::from_slice(
93 &mut target_vertical,
94 store.width,
95 store.height,
96 )?;
97 lab_store.bit_depth = into.bit_depth;
98
99 let lab_stride =
100 lab_store.width as u32 * COMPONENTS as u32 * std::mem::size_of::<f32>() as u32;
101 rgb_to_sigmoidal(
102 store.buffer.as_ref(),
103 store.width as u32 * COMPONENTS as u32,
104 lab_store.buffer.borrow_mut(),
105 lab_stride,
106 lab_store.width as u32,
107 lab_store.height as u32,
108 );
109
110 let new_immutable_store = ImageStore::<f32, COMPONENTS> {
111 buffer: std::borrow::Cow::Owned(target_vertical),
112 channels: COMPONENTS,
113 width: store.width,
114 height: store.height,
115 stride: store.width * COMPONENTS,
116 bit_depth: into.bit_depth,
117 };
118
119 let mut new_store = ImageStoreMut::<f32, COMPONENTS>::alloc(into.width, into.height);
120 self.scaler
121 .resize_rgb_f32(&new_immutable_store, &mut new_store)?;
122
123 let new_lab_stride =
124 new_store.width as u32 * COMPONENTS as u32 * std::mem::size_of::<f32>() as u32;
125
126 sigmoidal_to_rgb(
127 new_store.buffer.borrow(),
128 new_lab_stride,
129 into.buffer.borrow_mut(),
130 into.width as u32 * COMPONENTS as u32,
131 new_store.width as u32,
132 new_store.height as u32,
133 );
134 Ok(())
135 }
136
137 fn resize_rgba<'a>(
138 &'a self,
139 store: &ImageStore<'a, u8, 4>,
140 into: &mut ImageStoreMut<'a, u8, 4>,
141 premultiply_alpha: bool,
142 ) -> Result<(), PicScaleError> {
143 let new_size = into.get_size();
144 into.validate()?;
145 store.validate()?;
146 if store.width == 0 || store.height == 0 || new_size.width == 0 || new_size.height == 0 {
147 return Err(PicScaleError::ZeroImageDimensions);
148 }
149
150 if check_image_size_overflow(store.width, store.height, store.channels) {
151 return Err(PicScaleError::SourceImageIsTooLarge);
152 }
153
154 if check_image_size_overflow(new_size.width, new_size.height, store.channels) {
155 return Err(PicScaleError::DestinationImageIsTooLarge);
156 }
157
158 if store.width == new_size.width && store.height == new_size.height {
159 store.copied_to_mut(into);
160 return Ok(());
161 }
162
163 const COMPONENTS: usize = 4;
164
165 let mut target_vertical = vec![f32::default(); store.width * store.height * COMPONENTS];
166
167 let mut lab_store = ImageStoreMut::<f32, COMPONENTS>::from_slice(
168 &mut target_vertical,
169 store.width,
170 store.height,
171 )?;
172 lab_store.bit_depth = into.bit_depth;
173
174 let lab_stride =
175 lab_store.width as u32 * COMPONENTS as u32 * std::mem::size_of::<f32>() as u32;
176 rgba_to_sigmoidal(
177 store.buffer.as_ref(),
178 store.width as u32 * COMPONENTS as u32,
179 lab_store.buffer.borrow_mut(),
180 lab_stride,
181 lab_store.width as u32,
182 lab_store.height as u32,
183 );
184
185 let new_immutable_store = ImageStore::<f32, COMPONENTS> {
186 buffer: std::borrow::Cow::Owned(target_vertical),
187 channels: COMPONENTS,
188 width: store.width,
189 height: store.height,
190 stride: store.width * COMPONENTS,
191 bit_depth: into.bit_depth,
192 };
193
194 let mut new_store = ImageStoreMut::<f32, COMPONENTS>::alloc(into.width, into.height);
195 self.scaler
196 .resize_rgba_f32(&new_immutable_store, &mut new_store, premultiply_alpha)?;
197
198 let new_lab_stride =
199 new_store.width as u32 * COMPONENTS as u32 * std::mem::size_of::<f32>() as u32;
200
201 sigmoidal_to_rgba(
202 new_store.buffer.borrow(),
203 new_lab_stride,
204 into.buffer.borrow_mut(),
205 into.width as u32 * COMPONENTS as u32,
206 new_store.width as u32,
207 new_store.height as u32,
208 );
209 Ok(())
210 }
211}