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