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