1use crate::cpu_extensions::CpuExtensions;
2use crate::image_view::{try_pixel_type, ImageViewMut, IntoImageView, IntoImageViewMut};
3use crate::pixels::{F32x2, F32x4, U16x2, U16x4, U8x2, U8x4};
4use crate::{ImageError, ImageView, MulDivImagesError, PixelTrait, PixelType};
5
6#[derive(Default, Debug, Clone)]
28pub struct MulDiv {
29 cpu_extensions: CpuExtensions,
30}
31
32impl MulDiv {
33 pub fn new() -> Self {
34 Default::default()
35 }
36
37 pub fn cpu_extensions(&self) -> CpuExtensions {
38 self.cpu_extensions
39 }
40
41 pub unsafe fn set_cpu_extensions(&mut self, extensions: CpuExtensions) {
45 self.cpu_extensions = extensions;
46 }
47
48 pub fn multiply_alpha(
51 &self,
52 src_image: &impl IntoImageView,
53 dst_image: &mut impl IntoImageViewMut,
54 ) -> Result<(), MulDivImagesError> {
55 let src_pixel_type = try_pixel_type(src_image)?;
56 let dst_pixel_type = try_pixel_type(dst_image)?;
57 if src_pixel_type != dst_pixel_type {
58 return Err(MulDivImagesError::PixelTypesAreDifferent);
59 }
60
61 #[cfg(not(feature = "only_u8x4"))]
62 match src_pixel_type {
63 PixelType::U8x2 => self.multiply::<U8x2>(src_image, dst_image),
64 PixelType::U8x4 => self.multiply::<U8x4>(src_image, dst_image),
65 PixelType::U16x2 => self.multiply::<U16x2>(src_image, dst_image),
66 PixelType::U16x4 => self.multiply::<U16x4>(src_image, dst_image),
67 PixelType::F32x2 => self.multiply::<F32x2>(src_image, dst_image),
68 PixelType::F32x4 => self.multiply::<F32x4>(src_image, dst_image),
69 _ => Err(MulDivImagesError::ImageError(
70 ImageError::UnsupportedPixelType,
71 )),
72 }
73
74 #[cfg(feature = "only_u8x4")]
75 match src_pixel_type {
76 PixelType::U8x4 => self.multiply::<U8x4>(src_image, dst_image),
77 _ => Err(MulDivImagesError::ImageError(
78 ImageError::UnsupportedPixelType,
79 )),
80 }
81 }
82
83 #[inline]
84 fn multiply<P: PixelTrait>(
85 &self,
86 src_image: &impl IntoImageView,
87 dst_image: &mut impl IntoImageViewMut,
88 ) -> Result<(), MulDivImagesError> {
89 match (src_image.image_view(), dst_image.image_view_mut()) {
90 (Some(src), Some(mut dst)) => self.multiply_alpha_typed::<P>(&src, &mut dst),
91 _ => Err(MulDivImagesError::ImageError(
92 ImageError::UnsupportedPixelType,
93 )),
94 }
95 }
96
97 pub fn multiply_alpha_typed<P: PixelTrait>(
98 &self,
99 src_view: &impl ImageView<Pixel = P>,
100 dst_view: &mut impl ImageViewMut<Pixel = P>,
101 ) -> Result<(), MulDivImagesError> {
102 if src_view.width() != dst_view.width() || src_view.height() != dst_view.height() {
103 return Err(MulDivImagesError::SizeIsDifferent);
104 }
105 if src_view.width() > 0 && src_view.height() > 0 {
106 P::multiply_alpha(src_view, dst_view, self.cpu_extensions)?;
107 }
108 Ok(())
109 }
110
111 pub fn multiply_alpha_inplace(
113 &self,
114 image: &mut impl IntoImageViewMut,
115 ) -> Result<(), ImageError> {
116 let pixel_type = try_pixel_type(image)?;
117
118 #[cfg(not(feature = "only_u8x4"))]
119 match pixel_type {
120 PixelType::U8x2 => self.multiply_inplace::<U8x2>(image),
121 PixelType::U8x4 => self.multiply_inplace::<U8x4>(image),
122 PixelType::U16x2 => self.multiply_inplace::<U16x2>(image),
123 PixelType::U16x4 => self.multiply_inplace::<U16x4>(image),
124 PixelType::F32x2 => self.multiply_inplace::<F32x2>(image),
125 PixelType::F32x4 => self.multiply_inplace::<F32x4>(image),
126 _ => Err(ImageError::UnsupportedPixelType),
127 }
128
129 #[cfg(feature = "only_u8x4")]
130 match pixel_type {
131 PixelType::U8x4 => self.multiply_inplace::<U8x4>(image),
132 _ => Err(ImageError::UnsupportedPixelType),
133 }
134 }
135
136 #[inline]
137 fn multiply_inplace<P: PixelTrait>(
138 &self,
139 image: &mut impl IntoImageViewMut,
140 ) -> Result<(), ImageError> {
141 match image.image_view_mut() {
142 Some(mut view) => self.multiply_alpha_inplace_typed::<P>(&mut view),
143 _ => Err(ImageError::UnsupportedPixelType),
144 }
145 }
146
147 pub fn multiply_alpha_inplace_typed<P: PixelTrait>(
148 &self,
149 img_view: &mut impl ImageViewMut<Pixel = P>,
150 ) -> Result<(), ImageError> {
151 if img_view.width() > 0 && img_view.height() > 0 {
152 P::multiply_alpha_inplace(img_view, self.cpu_extensions)
153 } else {
154 Ok(())
155 }
156 }
157
158 pub fn divide_alpha(
161 &self,
162 src_image: &impl IntoImageView,
163 dst_image: &mut impl IntoImageViewMut,
164 ) -> Result<(), MulDivImagesError> {
165 let src_pixel_type = try_pixel_type(src_image)?;
166 let dst_pixel_type = try_pixel_type(dst_image)?;
167 if src_pixel_type != dst_pixel_type {
168 return Err(MulDivImagesError::PixelTypesAreDifferent);
169 }
170
171 #[cfg(not(feature = "only_u8x4"))]
172 match src_pixel_type {
173 PixelType::U8x2 => self.divide::<U8x2>(src_image, dst_image),
174 PixelType::U8x4 => self.divide::<U8x4>(src_image, dst_image),
175 PixelType::U16x2 => self.divide::<U16x2>(src_image, dst_image),
176 PixelType::U16x4 => self.divide::<U16x4>(src_image, dst_image),
177 PixelType::F32x2 => self.divide::<F32x2>(src_image, dst_image),
178 PixelType::F32x4 => self.divide::<F32x4>(src_image, dst_image),
179 _ => Err(MulDivImagesError::ImageError(
180 ImageError::UnsupportedPixelType,
181 )),
182 }
183
184 #[cfg(feature = "only_u8x4")]
185 match src_pixel_type {
186 PixelType::U8x4 => self.divide::<U8x4>(src_image, dst_image),
187 _ => Err(MulDivImagesError::ImageError(
188 ImageError::UnsupportedPixelType,
189 )),
190 }
191 }
192
193 #[inline]
194 fn divide<P: PixelTrait>(
195 &self,
196 src_image: &impl IntoImageView,
197 dst_image: &mut impl IntoImageViewMut,
198 ) -> Result<(), MulDivImagesError> {
199 match (src_image.image_view(), dst_image.image_view_mut()) {
200 (Some(src), Some(mut dst)) => self.divide_alpha_typed::<P>(&src, &mut dst),
201 _ => Err(MulDivImagesError::ImageError(
202 ImageError::UnsupportedPixelType,
203 )),
204 }
205 }
206
207 pub fn divide_alpha_typed<P: PixelTrait>(
208 &self,
209 src_view: &impl ImageView<Pixel = P>,
210 dst_view: &mut impl ImageViewMut<Pixel = P>,
211 ) -> Result<(), MulDivImagesError> {
212 if src_view.width() != dst_view.width() || src_view.height() != dst_view.height() {
213 return Err(MulDivImagesError::SizeIsDifferent);
214 }
215 if src_view.width() > 0 && src_view.height() > 0 {
216 P::divide_alpha(src_view, dst_view, self.cpu_extensions)?;
217 }
218 Ok(())
219 }
220
221 pub fn divide_alpha_inplace(
223 &self,
224 image: &mut impl IntoImageViewMut,
225 ) -> Result<(), ImageError> {
226 let pixel_type = try_pixel_type(image)?;
227
228 #[cfg(not(feature = "only_u8x4"))]
229 match pixel_type {
230 PixelType::U8x2 => self.divide_inplace::<U8x2>(image),
231 PixelType::U8x4 => self.divide_inplace::<U8x4>(image),
232 PixelType::U16x2 => self.divide_inplace::<U16x2>(image),
233 PixelType::U16x4 => self.divide_inplace::<U16x4>(image),
234 PixelType::F32x2 => self.divide_inplace::<F32x2>(image),
235 PixelType::F32x4 => self.divide_inplace::<F32x4>(image),
236 _ => Err(ImageError::UnsupportedPixelType),
237 }
238
239 #[cfg(feature = "only_u8x4")]
240 match pixel_type {
241 PixelType::U8x4 => self.divide_inplace::<U8x4>(image),
242 _ => Err(ImageError::UnsupportedPixelType),
243 }
244 }
245
246 #[inline]
247 fn divide_inplace<P: PixelTrait>(
248 &self,
249 image: &mut impl IntoImageViewMut,
250 ) -> Result<(), ImageError> {
251 match image.image_view_mut() {
252 Some(mut view) => self.divide_alpha_inplace_typed::<P>(&mut view),
253 _ => Err(ImageError::UnsupportedPixelType),
254 }
255 }
256
257 pub fn divide_alpha_inplace_typed<P: PixelTrait>(
258 &self,
259 img_view: &mut impl ImageViewMut<Pixel = P>,
260 ) -> Result<(), ImageError> {
261 if img_view.width() > 0 && img_view.height() > 0 {
262 P::divide_alpha_inplace(img_view, self.cpu_extensions)
263 } else {
264 Ok(())
265 }
266 }
267
268 pub fn is_supported(&self, pixel_type: PixelType) -> bool {
269 #[cfg(not(feature = "only_u8x4"))]
270 {
271 matches!(
272 pixel_type,
273 PixelType::U8x2
274 | PixelType::U8x4
275 | PixelType::U16x2
276 | PixelType::U16x4
277 | PixelType::F32x2
278 | PixelType::F32x4
279 )
280 }
281 #[cfg(feature = "only_u8x4")]
282 {
283 matches!(pixel_type, PixelType::U8x4)
284 }
285 }
286}