fast_image_resize/
mul_div.rs

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/// Methods of this structure used to multiply or divide color-channels (RGB or Luma)
7/// by alpha-channel. Supported pixel types: U8x2, U8x4, U16x2, U16x4, F32x2 and F32x4.
8///
9/// By default, the instance of `MulDiv` created with the best CPU-extension provided by your CPU.
10/// You can change this by using method [MulDiv::set_cpu_extensions].
11///
12/// # Examples
13///
14/// ```
15/// use fast_image_resize::pixels::PixelType;
16/// use fast_image_resize::images::Image;
17/// use fast_image_resize::MulDiv;
18///
19/// let width: u32 = 10;
20/// let height: u32 = 7;
21/// let src_image = Image::new(width, height, PixelType::U8x4);
22/// let mut dst_image = Image::new(width, height, PixelType::U8x4);
23///
24/// let mul_div = MulDiv::new();
25/// mul_div.multiply_alpha(&src_image, &mut dst_image).unwrap();
26/// ```
27#[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    /// # Safety
42    /// This is unsafe because this method allows you to set a CPU-extensions
43    /// that is not actually supported by your CPU.
44    pub unsafe fn set_cpu_extensions(&mut self, extensions: CpuExtensions) {
45        self.cpu_extensions = extensions;
46    }
47
48    /// Multiplies color-channels (RGB or Luma) of source image by alpha-channel and store
49    /// result into destination image.
50    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    /// Multiplies color-channels (RGB or Luma) of image by alpha-channel inplace.
112    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    /// Divides color-channels (RGB or Luma) of source image by alpha-channel and store
159    /// result into destination image.
160    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    /// Divides color-channels (RGB or Luma) of image by alpha-channel inplace.
222    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}