pic_scale/colors/
xyz_scaler.rs1use colorutils_rs::{
30 SRGB_TO_XYZ_D65, TransferFunction, XYZ_TO_SRGB_D65, rgba_to_xyz_with_alpha, srgb_to_xyz,
31 xyz_to_srgb, xyz_with_alpha_to_rgba,
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 XYZScaler {
43 pub(crate) scaler: Scaler,
44}
45
46impl XYZScaler {
47 pub fn new(filter: ResamplingFunction) -> Self {
48 XYZScaler {
49 scaler: Scaler::new(filter),
50 }
51 }
52}
53
54struct XyzRgbSplitter {}
55
56impl Splitter<u8, f32, 3> for XyzRgbSplitter {
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 srgb_to_xyz(&from.to_colorutils_buffer(), &mut dst_buffer)
64 .map_err(|x| PicScaleError::Generic(x.to_string()))
65 }
66
67 fn merge(
68 &self,
69 from: &ImageStore<'_, f32, 3>,
70 into: &mut ImageStoreMut<'_, u8, 3>,
71 ) -> Result<(), PicScaleError> {
72 let mut dst_buffer = into.to_colorutils_buffer_mut();
73 xyz_to_srgb(&from.to_colorutils_buffer(), &mut dst_buffer)
74 .map_err(|x| PicScaleError::Generic(x.to_string()))
75 }
76
77 fn bit_depth(&self) -> usize {
78 8
79 }
80}
81
82struct XyzRgbaSplitter {}
83
84impl Splitter<u8, f32, 4> for XyzRgbaSplitter {
85 fn split(
86 &self,
87 from: &ImageStore<'_, u8, 4>,
88 into: &mut ImageStoreMut<'_, f32, 4>,
89 ) -> Result<(), PicScaleError> {
90 let mut dst_buffer = into.to_colorutils_buffer_mut();
91
92 rgba_to_xyz_with_alpha(
93 &from.to_colorutils_buffer(),
94 &mut dst_buffer,
95 &SRGB_TO_XYZ_D65,
96 TransferFunction::Srgb,
97 )
98 .map_err(|x| PicScaleError::Generic(x.to_string()))
99 }
100
101 fn merge(
102 &self,
103 from: &ImageStore<'_, f32, 4>,
104 into: &mut ImageStoreMut<'_, u8, 4>,
105 ) -> Result<(), PicScaleError> {
106 let mut dst_buffer = into.to_colorutils_buffer_mut();
107 xyz_with_alpha_to_rgba(
108 &from.to_colorutils_buffer(),
109 &mut dst_buffer,
110 &XYZ_TO_SRGB_D65,
111 TransferFunction::Srgb,
112 )
113 .map_err(|x| PicScaleError::Generic(x.to_string()))
114 }
115
116 fn bit_depth(&self) -> usize {
117 8
118 }
119}
120
121impl XYZScaler {
122 pub fn set_threading_policy(&mut self, threading_policy: ThreadingPolicy) -> Self {
123 self.scaler.threading_policy = threading_policy;
124 *self
125 }
126
127 pub fn plan_rgb_resampling(
128 &self,
129 source_size: ImageSize,
130 target_size: ImageSize,
131 ) -> Result<Arc<Resampling<u8, 3>>, PicScaleError> {
132 let intercept = self
133 .scaler
134 .plan_rgb_resampling_f32(source_size, target_size)?;
135 let scratch_size = intercept.scratch_size();
136 Ok(Arc::new(SplitPlanInterceptor {
137 intercept,
138 splitter: Arc::new(XyzRgbSplitter {}),
139 inner_scratch: scratch_size,
140 }))
141 }
142
143 pub fn plan_rgba_resampling(
144 &self,
145 source_size: ImageSize,
146 target_size: ImageSize,
147 premultiply_alpha: bool,
148 ) -> Result<Arc<Resampling<u8, 4>>, PicScaleError> {
149 let intercept =
150 self.scaler
151 .plan_rgba_resampling_f32(source_size, target_size, premultiply_alpha)?;
152 let scratch_size = intercept.scratch_size();
153 Ok(Arc::new(SplitPlanInterceptor {
154 intercept,
155 splitter: Arc::new(XyzRgbaSplitter {}),
156 inner_scratch: scratch_size,
157 }))
158 }
159}