1use crate::colors::common_splitter::{SplitPlanInterceptor, Splitter};
30use crate::plan::Resampling;
31use crate::validation::PicScaleError;
32use crate::{ImageSize, ImageStore, ImageStoreMut, ResamplingFunction, Scaler, ThreadingPolicy};
33use colorutils_rs::{
34 SRGB_TO_XYZ_D65, TransferFunction, XYZ_TO_SRGB_D65, rgb_to_sigmoidal, rgba_to_xyz_with_alpha,
35 sigmoidal_to_rgb, xyz_with_alpha_to_rgba,
36};
37use std::sync::Arc;
38
39#[derive(Debug, Copy, Clone)]
40pub struct SigmoidalScaler {
42 pub(crate) scaler: Scaler,
43}
44
45impl SigmoidalScaler {
46 pub fn new(filter: ResamplingFunction) -> Self {
47 SigmoidalScaler {
48 scaler: Scaler::new(filter),
49 }
50 }
51}
52
53struct SigmoidalRgbSplitter {}
54
55impl Splitter<u8, f32, 3> for SigmoidalRgbSplitter {
56 fn split(&self, from: &ImageStore<'_, u8, 3>, into: &mut ImageStoreMut<'_, f32, 3>) {
57 let lab_stride = into.width as u32 * 3u32 * size_of::<f32>() as u32;
58
59 rgb_to_sigmoidal(
60 from.buffer.as_ref(),
61 from.width as u32 * 3u32,
62 into.buffer.borrow_mut(),
63 lab_stride,
64 into.width as u32,
65 into.height as u32,
66 );
67 }
68
69 fn merge(&self, from: &ImageStore<'_, f32, 3>, into: &mut ImageStoreMut<'_, u8, 3>) {
70 let new_lab_stride = into.width as u32 * 3 * size_of::<f32>() as u32;
71 sigmoidal_to_rgb(
72 from.buffer.as_ref(),
73 new_lab_stride,
74 into.buffer.borrow_mut(),
75 into.width as u32 * 3,
76 into.width as u32,
77 into.height as u32,
78 );
79 }
80
81 fn bit_depth(&self) -> usize {
82 8
83 }
84}
85
86struct SigmoidalRgbaSplitter {}
87
88impl Splitter<u8, f32, 4> for SigmoidalRgbaSplitter {
89 fn split(&self, from: &ImageStore<'_, u8, 4>, into: &mut ImageStoreMut<'_, f32, 4>) {
90 let lab_stride = into.width as u32 * 4u32 * size_of::<f32>() as u32;
91
92 rgba_to_xyz_with_alpha(
93 from.buffer.as_ref(),
94 from.width as u32 * 4u32,
95 into.buffer.borrow_mut(),
96 lab_stride,
97 into.width as u32,
98 into.height as u32,
99 &SRGB_TO_XYZ_D65,
100 TransferFunction::Srgb,
101 );
102 }
103
104 fn merge(&self, from: &ImageStore<'_, f32, 4>, into: &mut ImageStoreMut<'_, u8, 4>) {
105 let new_lab_stride = into.width as u32 * 4 * size_of::<f32>() as u32;
106 xyz_with_alpha_to_rgba(
107 from.buffer.as_ref(),
108 new_lab_stride,
109 into.buffer.borrow_mut(),
110 into.width as u32 * 4,
111 into.width as u32,
112 into.height as u32,
113 &XYZ_TO_SRGB_D65,
114 TransferFunction::Srgb,
115 );
116 }
117
118 fn bit_depth(&self) -> usize {
119 8
120 }
121}
122
123impl SigmoidalScaler {
124 pub fn set_threading_policy(&mut self, threading_policy: ThreadingPolicy) -> Self {
125 self.scaler.set_threading_policy(threading_policy);
126 *self
127 }
128
129 pub fn plan_rgb_resampling(
130 &self,
131 source_size: ImageSize,
132 target_size: ImageSize,
133 ) -> Result<Arc<Resampling<u8, 3>>, PicScaleError> {
134 let intercept = self
135 .scaler
136 .plan_rgb_resampling_f32(source_size, target_size)?;
137 let scratch_size = intercept.scratch_size();
138 Ok(Arc::new(SplitPlanInterceptor {
139 intercept,
140 splitter: Arc::new(SigmoidalRgbSplitter {}),
141 inner_scratch: scratch_size,
142 }))
143 }
144
145 pub fn plan_rgba_resampling(
146 &self,
147 source_size: ImageSize,
148 target_size: ImageSize,
149 premultiply_alpha: bool,
150 ) -> Result<Arc<Resampling<u8, 4>>, PicScaleError> {
151 let intercept =
152 self.scaler
153 .plan_rgba_resampling_f32(source_size, target_size, premultiply_alpha)?;
154 let scratch_size = intercept.scratch_size();
155 Ok(Arc::new(SplitPlanInterceptor {
156 intercept,
157 splitter: Arc::new(SigmoidalRgbaSplitter {}),
158 inner_scratch: scratch_size,
159 }))
160 }
161}