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(&self, from: &ImageStore<'_, u8, 3>, into: &mut ImageStoreMut<'_, f32, 3>) {
49 let lab_stride = into.width as u32 * 3u32 * size_of::<f32>() as u32;
50
51 rgb_to_lab(
52 from.buffer.as_ref(),
53 from.width as u32 * 3u32,
54 into.buffer.borrow_mut(),
55 lab_stride,
56 into.width as u32,
57 into.height as u32,
58 &SRGB_TO_XYZ_D65,
59 TransferFunction::Srgb,
60 );
61 }
62
63 fn merge(&self, from: &ImageStore<'_, f32, 3>, into: &mut ImageStoreMut<'_, u8, 3>) {
64 let new_lab_stride = into.width as u32 * 3 * size_of::<f32>() as u32;
65 lab_to_srgb(
66 from.buffer.as_ref(),
67 new_lab_stride,
68 into.buffer.borrow_mut(),
69 into.width as u32 * 3,
70 into.width as u32,
71 into.height as u32,
72 );
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(&self, from: &ImageStore<'_, u8, 4>, into: &mut ImageStoreMut<'_, f32, 4>) {
83 let lab_stride = into.width as u32 * 4u32 * size_of::<f32>() as u32;
84
85 rgba_to_lab_with_alpha(
86 from.buffer.as_ref(),
87 from.width as u32 * 4u32,
88 into.buffer.borrow_mut(),
89 lab_stride,
90 into.width as u32,
91 into.height as u32,
92 &SRGB_TO_XYZ_D65,
93 TransferFunction::Srgb,
94 );
95 }
96
97 fn merge(&self, from: &ImageStore<'_, f32, 4>, into: &mut ImageStoreMut<'_, u8, 4>) {
98 let new_lab_stride = into.width as u32 * 4 * size_of::<f32>() as u32;
99 lab_with_alpha_to_rgba(
100 from.buffer.as_ref(),
101 new_lab_stride,
102 into.buffer.borrow_mut(),
103 into.width as u32 * 4,
104 into.width as u32,
105 into.height as u32,
106 &XYZ_TO_SRGB_D65,
107 TransferFunction::Srgb,
108 );
109 }
110
111 fn bit_depth(&self) -> usize {
112 8
113 }
114}
115
116impl LabScaler {
117 pub fn new(filter: ResamplingFunction) -> Self {
118 LabScaler {
119 scaler: Scaler::new(filter),
120 }
121 }
122}
123
124impl LabScaler {
125 pub fn set_threading_policy(&mut self, threading_policy: ThreadingPolicy) {
126 self.scaler.threading_policy = threading_policy;
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(LabRgbSplitter {}),
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(LabRgbaSplitter {}),
158 inner_scratch: scratch_size,
159 }))
160 }
161}