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