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