pic_scale/
image_store.rs

1/*
2 * Copyright (c) Radzivon Bartoshyk. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1.  Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * 2.  Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * 3.  Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29use crate::alpha_check::has_non_constant_cap_alpha_rgba_f32;
30#[cfg(feature = "nightly_f16")]
31use crate::alpha_handle_f16::{premultiply_alpha_rgba_f16, unpremultiply_alpha_rgba_f16};
32use crate::alpha_handle_f32::{premultiply_alpha_rgba_f32, unpremultiply_alpha_rgba_f32};
33use crate::alpha_handle_u16::{premultiply_alpha_rgba_u16, unpremultiply_alpha_rgba_u16};
34use crate::alpha_handle_u8::{premultiply_alpha_rgba, unpremultiply_alpha_rgba};
35use crate::pic_scale_error::{PicScaleBufferMismatch, PicScaleError};
36use crate::ImageSize;
37#[cfg(feature = "nightly_f16")]
38use core::f16;
39use rayon::ThreadPool;
40use std::borrow::Cow;
41use std::fmt::Debug;
42
43/// Holds an image
44///
45/// # Arguments
46/// `N` - count of channels
47///
48/// # Examples
49/// ImageStore<u8, 4> - represents RGBA
50/// ImageStore<u8, 3> - represents RGB
51/// ImageStore<f32, 3> - represents RGB in f32 and etc
52#[derive(Debug, Clone)]
53pub struct ImageStore<'a, T, const N: usize>
54where
55    T: Clone + Copy + Debug,
56{
57    pub buffer: std::borrow::Cow<'a, [T]>,
58    /// Channels in the image
59    pub channels: usize,
60    /// Image width
61    pub width: usize,
62    /// Image height
63    pub height: usize,
64    /// Image stride, if stride is zero then it considered to be `width * N`
65    pub stride: usize,
66    /// This is private field, currently used only for u16, will be automatically passed from upper func
67    pub bit_depth: usize,
68}
69
70/// Holds an image
71///
72/// # Arguments
73/// `N` - count of channels
74///
75/// # Examples
76/// ImageStore<u8, 4> - represents RGBA
77/// ImageStore<u8, 3> - represents RGB
78/// ImageStore<f32, 3> - represents RGB in f32 and etc
79#[derive(Debug)]
80pub struct ImageStoreMut<'a, T, const N: usize>
81where
82    T: Clone + Copy + Debug,
83{
84    pub buffer: BufferStore<'a, T>,
85    /// Channels in the image
86    pub channels: usize,
87    /// Image width
88    pub width: usize,
89    /// Image height
90    pub height: usize,
91    /// Image stride, if stride is zero then it considered to be `width * N`
92    pub stride: usize,
93    /// Required for `u16` images
94    pub bit_depth: usize,
95}
96
97pub(crate) trait CheckStoreDensity {
98    fn should_have_bit_depth(&self) -> bool;
99}
100
101#[derive(Debug)]
102pub enum BufferStore<'a, T: Copy + Debug> {
103    Borrowed(&'a mut [T]),
104    Owned(Vec<T>),
105}
106
107impl<T: Copy + Debug> BufferStore<'_, T> {
108    #[allow(clippy::should_implement_trait)]
109    pub fn borrow(&self) -> &[T] {
110        match self {
111            Self::Borrowed(p_ref) => p_ref,
112            Self::Owned(vec) => vec,
113        }
114    }
115
116    #[allow(clippy::should_implement_trait)]
117    pub fn borrow_mut(&mut self) -> &mut [T] {
118        match self {
119            Self::Borrowed(p_ref) => p_ref,
120            Self::Owned(vec) => vec,
121        }
122    }
123}
124
125impl<'a, T, const N: usize> ImageStore<'a, T, N>
126where
127    T: Clone + Copy + Debug + Default,
128{
129    pub fn new(
130        slice_ref: Vec<T>,
131        width: usize,
132        height: usize,
133    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
134        let expected_size = width * height * N;
135        if slice_ref.len() != width * height * N {
136            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
137                expected: expected_size,
138                width,
139                height,
140                channels: N,
141                slice_len: slice_ref.len(),
142            }));
143        }
144        Ok(ImageStore::<T, N> {
145            buffer: std::borrow::Cow::Owned(slice_ref),
146            channels: N,
147            width,
148            height,
149            stride: width * N,
150            bit_depth: 0,
151        })
152    }
153
154    pub fn borrow(
155        slice_ref: &'a [T],
156        width: usize,
157        height: usize,
158    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
159        let expected_size = width * height * N;
160        if slice_ref.len() != width * height * N {
161            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
162                expected: expected_size,
163                width,
164                height,
165                channels: N,
166                slice_len: slice_ref.len(),
167            }));
168        }
169        Ok(ImageStore::<T, N> {
170            buffer: Cow::Borrowed(slice_ref),
171            channels: N,
172            width,
173            height,
174            stride: width * N,
175            bit_depth: 0,
176        })
177    }
178
179    pub fn alloc(width: usize, height: usize) -> ImageStore<'a, T, N> {
180        let vc = vec![T::default(); width * N * height];
181        ImageStore::<T, N> {
182            buffer: std::borrow::Cow::Owned(vc),
183            channels: N,
184            width,
185            height,
186            stride: width * N,
187            bit_depth: 0,
188        }
189    }
190}
191
192impl<const N: usize> CheckStoreDensity for ImageStoreMut<'_, u8, N> {
193    fn should_have_bit_depth(&self) -> bool {
194        false
195    }
196}
197
198impl<const N: usize> CheckStoreDensity for ImageStoreMut<'_, f32, N> {
199    fn should_have_bit_depth(&self) -> bool {
200        false
201    }
202}
203
204#[cfg(feature = "nightly_f16")]
205impl<const N: usize> CheckStoreDensity for ImageStoreMut<'_, f16, N> {
206    fn should_have_bit_depth(&self) -> bool {
207        false
208    }
209}
210
211impl<const N: usize> CheckStoreDensity for ImageStoreMut<'_, u16, N> {
212    fn should_have_bit_depth(&self) -> bool {
213        true
214    }
215}
216
217impl<T, const N: usize> ImageStoreMut<'_, T, N>
218where
219    T: Clone + Copy + Debug + Default,
220{
221    pub(crate) fn validate(&self) -> Result<(), PicScaleError> {
222        let expected_size = self.stride() * self.height;
223        if self.buffer.borrow().len() != self.stride() * self.height {
224            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
225                expected: expected_size,
226                width: self.width,
227                height: self.height,
228                channels: N,
229                slice_len: self.buffer.borrow().len(),
230            }));
231        }
232        if self.stride < self.width * N {
233            return Err(PicScaleError::InvalidStride(self.width * N, self.stride));
234        }
235        Ok(())
236    }
237}
238
239impl<T, const N: usize> ImageStore<'_, T, N>
240where
241    T: Clone + Copy + Debug + Default,
242{
243    pub(crate) fn validate(&self) -> Result<(), PicScaleError> {
244        let expected_size = self.stride() * self.height;
245        if self.buffer.as_ref().len() != self.stride() * self.height {
246            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
247                expected: expected_size,
248                width: self.width,
249                height: self.height,
250                channels: N,
251                slice_len: self.buffer.as_ref().len(),
252            }));
253        }
254        if self.stride < self.width * N {
255            return Err(PicScaleError::InvalidStride(self.width * N, self.stride));
256        }
257        Ok(())
258    }
259}
260
261impl<'a, T, const N: usize> ImageStoreMut<'a, T, N>
262where
263    T: Clone + Copy + Debug + Default,
264{
265    /// Creates new mutable storage from vector
266    ///
267    /// Always sets bit-depth to `0`
268    pub fn new(
269        slice_ref: Vec<T>,
270        width: usize,
271        height: usize,
272    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
273        let expected_size = width * height * N;
274        if slice_ref.len() != width * height * N {
275            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
276                expected: expected_size,
277                width,
278                height,
279                channels: N,
280                slice_len: slice_ref.len(),
281            }));
282        }
283        Ok(ImageStoreMut::<T, N> {
284            buffer: BufferStore::Owned(slice_ref),
285            channels: N,
286            width,
287            height,
288            stride: width * N,
289            bit_depth: 0,
290        })
291    }
292
293    /// Creates new mutable storage from slice
294    ///
295    /// Always sets bit-depth to `0`
296    pub fn borrow(
297        slice_ref: &'a mut [T],
298        width: usize,
299        height: usize,
300    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
301        let expected_size = width * height * N;
302        if slice_ref.len() != width * height * N {
303            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
304                expected: expected_size,
305                width,
306                height,
307                channels: N,
308                slice_len: slice_ref.len(),
309            }));
310        }
311        Ok(ImageStoreMut::<T, N> {
312            buffer: BufferStore::Borrowed(slice_ref),
313            channels: N,
314            width,
315            height,
316            stride: width * N,
317            bit_depth: 0,
318        })
319    }
320
321    /// Allocates new mutable image storage
322    ///
323    /// Always sets bit depth to `0`
324    pub fn alloc(width: usize, height: usize) -> ImageStoreMut<'a, T, N> {
325        let vc = vec![T::default(); width * N * height];
326        ImageStoreMut::<T, N> {
327            buffer: BufferStore::Owned(vc),
328            channels: N,
329            width,
330            height,
331            stride: width * N,
332            bit_depth: 0,
333        }
334    }
335
336    /// Allocates new mutable image storage with required bit-depth
337    pub fn alloc_with_depth(
338        width: usize,
339        height: usize,
340        bit_depth: usize,
341    ) -> ImageStoreMut<'a, T, N> {
342        let vc = vec![T::default(); width * N * height];
343        ImageStoreMut::<T, N> {
344            buffer: BufferStore::Owned(vc),
345            channels: N,
346            width,
347            height,
348            stride: width * N,
349            bit_depth,
350        }
351    }
352}
353
354impl<T, const N: usize> ImageStoreMut<'_, T, N>
355where
356    T: Clone + Copy + Debug,
357{
358    /// Returns safe stride
359    ///
360    /// If stride set to 0 then returns `width * N`
361    #[inline]
362    pub fn stride(&self) -> usize {
363        if self.stride == 0 {
364            return self.width * N;
365        }
366        self.stride
367    }
368}
369
370impl<T, const N: usize> ImageStore<'_, T, N>
371where
372    T: Clone + Copy + Debug,
373{
374    /// Returns safe stride
375    ///
376    /// If stride set to 0 then returns `width * N`
377    #[inline]
378    pub fn stride(&self) -> usize {
379        if self.stride == 0 {
380            return self.width * N;
381        }
382        self.stride
383    }
384}
385
386impl<'a, T, const N: usize> ImageStore<'a, T, N>
387where
388    T: Clone + Copy + Debug,
389{
390    /// Returns bounded image size
391    pub fn get_size(&self) -> ImageSize {
392        ImageSize::new(self.width, self.height)
393    }
394
395    pub fn as_bytes(&self) -> &[T] {
396        match &self.buffer {
397            Cow::Borrowed(br) => br,
398            Cow::Owned(v) => v.as_ref(),
399        }
400    }
401
402    pub fn from_slice(
403        slice_ref: &'a [T],
404        width: usize,
405        height: usize,
406    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
407        let expected_size = width * height * N;
408        if slice_ref.len() != width * height * N {
409            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
410                expected: expected_size,
411                width,
412                height,
413                channels: N,
414                slice_len: slice_ref.len(),
415            }));
416        }
417        Ok(ImageStore::<T, N> {
418            buffer: std::borrow::Cow::Borrowed(slice_ref),
419            channels: N,
420            width,
421            height,
422            stride: width * N,
423            bit_depth: 0,
424        })
425    }
426
427    pub fn copied<'b>(&self) -> ImageStore<'b, T, N> {
428        ImageStore::<T, N> {
429            buffer: std::borrow::Cow::Owned(self.buffer.as_ref().to_vec()),
430            channels: N,
431            width: self.width,
432            height: self.height,
433            stride: self.width * N,
434            bit_depth: self.bit_depth,
435        }
436    }
437
438    pub fn copied_to_mut(&self, into: &mut ImageStoreMut<T, N>) {
439        let into_stride = into.stride();
440        for (src_row, dst_row) in self
441            .buffer
442            .as_ref()
443            .chunks_exact(self.stride())
444            .zip(into.buffer.borrow_mut().chunks_exact_mut(into_stride))
445        {
446            for (&src, dst) in src_row.iter().zip(dst_row.iter_mut()) {
447                *dst = src;
448            }
449        }
450    }
451}
452
453impl<'a, T, const N: usize> ImageStoreMut<'a, T, N>
454where
455    T: Clone + Copy + Debug,
456{
457    /// Returns bounded image size
458    pub fn get_size(&self) -> ImageSize {
459        ImageSize::new(self.width, self.height)
460    }
461
462    pub fn as_bytes(&self) -> &[T] {
463        match &self.buffer {
464            BufferStore::Borrowed(p) => p,
465            BufferStore::Owned(v) => v,
466        }
467    }
468
469    pub fn from_slice(
470        slice_ref: &'a mut [T],
471        width: usize,
472        height: usize,
473    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
474        let expected_size = width * height * N;
475        if slice_ref.len() != width * height * N {
476            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
477                expected: expected_size,
478                width,
479                height,
480                channels: N,
481                slice_len: slice_ref.len(),
482            }));
483        }
484        Ok(ImageStoreMut::<T, N> {
485            buffer: BufferStore::Borrowed(slice_ref),
486            channels: N,
487            width,
488            height,
489            stride: width * N,
490            bit_depth: 0,
491        })
492    }
493
494    pub fn copied<'b>(&self) -> ImageStoreMut<'b, T, N> {
495        ImageStoreMut::<T, N> {
496            buffer: BufferStore::Owned(self.buffer.borrow().to_vec()),
497            channels: N,
498            width: self.width,
499            height: self.height,
500            stride: self.width * N,
501            bit_depth: self.bit_depth,
502        }
503    }
504
505    pub fn to_immutable(&self) -> ImageStore<'_, T, N> {
506        ImageStore::<T, N> {
507            buffer: std::borrow::Cow::Owned(self.buffer.borrow().to_owned()),
508            channels: N,
509            width: self.width,
510            height: self.height,
511            stride: self.width * N,
512            bit_depth: self.bit_depth,
513        }
514    }
515}
516
517pub(crate) trait AssociateAlpha<T: Clone + Copy + Debug, const N: usize> {
518    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, T, N>, pool: &Option<ThreadPool>);
519    fn is_alpha_premultiplication_needed(&self) -> bool;
520}
521
522pub(crate) trait UnassociateAlpha<T: Clone + Copy + Debug, const N: usize> {
523    fn unpremultiply_alpha(&mut self, pool: &Option<ThreadPool>);
524}
525
526impl AssociateAlpha<u8, 4> for ImageStore<'_, u8, 4> {
527    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u8, 4>, pool: &Option<ThreadPool>) {
528        let dst_stride = into.stride();
529        let dst = into.buffer.borrow_mut();
530        let src = self.buffer.as_ref();
531        premultiply_alpha_rgba(
532            dst,
533            dst_stride,
534            src,
535            self.width,
536            self.height,
537            self.stride(),
538            pool,
539        );
540    }
541
542    #[cfg(not(any(
543        any(target_arch = "x86_64", target_arch = "x86"),
544        all(target_arch = "aarch64", target_feature = "neon")
545    )))]
546    fn is_alpha_premultiplication_needed(&self) -> bool {
547        use crate::alpha_check::has_non_constant_cap_alpha_rgba8;
548        has_non_constant_cap_alpha_rgba8(self.buffer.as_ref(), self.width, self.stride())
549    }
550
551    #[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
552    fn is_alpha_premultiplication_needed(&self) -> bool {
553        use crate::neon::neon_has_non_constant_cap_alpha_rgba8;
554        neon_has_non_constant_cap_alpha_rgba8(self.buffer.as_ref(), self.width, self.stride())
555    }
556
557    #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
558    fn is_alpha_premultiplication_needed(&self) -> bool {
559        use crate::alpha_check::has_non_constant_cap_alpha_rgba8;
560        #[cfg(feature = "sse")]
561        use crate::sse::sse_has_non_constant_cap_alpha_rgba8;
562        #[cfg(all(target_arch = "x86_64", feature = "nightly_avx512"))]
563        if std::arch::is_x86_feature_detected!("avx512bw") {
564            use crate::avx512::avx512_has_non_constant_cap_alpha_rgba8;
565            return avx512_has_non_constant_cap_alpha_rgba8(
566                self.buffer.as_ref(),
567                self.width,
568                self.stride(),
569            );
570        }
571        #[cfg(all(target_arch = "x86_64", feature = "avx"))]
572        if std::arch::is_x86_feature_detected!("avx2") {
573            use crate::avx2::avx_has_non_constant_cap_alpha_rgba8;
574            return avx_has_non_constant_cap_alpha_rgba8(
575                self.buffer.as_ref(),
576                self.width,
577                self.stride(),
578            );
579        }
580        #[cfg(feature = "sse")]
581        if std::arch::is_x86_feature_detected!("sse4.1") {
582            return sse_has_non_constant_cap_alpha_rgba8(
583                self.buffer.as_ref(),
584                self.width,
585                self.stride(),
586            );
587        }
588        has_non_constant_cap_alpha_rgba8(self.buffer.as_ref(), self.width, self.stride())
589    }
590}
591
592impl UnassociateAlpha<u8, 4> for ImageStoreMut<'_, u8, 4> {
593    fn unpremultiply_alpha(&mut self, pool: &Option<ThreadPool>) {
594        let src_stride = self.stride();
595        let dst = self.buffer.borrow_mut();
596        unpremultiply_alpha_rgba(dst, self.width, self.height, src_stride, pool);
597    }
598}
599
600impl AssociateAlpha<u16, 4> for ImageStore<'_, u16, 4> {
601    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u16, 4>, pool: &Option<ThreadPool>) {
602        let dst_stride = into.stride();
603        let dst = into.buffer.borrow_mut();
604        let src = self.buffer.as_ref();
605        premultiply_alpha_rgba_u16(
606            dst,
607            dst_stride,
608            src,
609            self.width,
610            self.height,
611            self.stride(),
612            into.bit_depth,
613            pool,
614        );
615    }
616
617    #[cfg(not(any(
618        any(target_arch = "x86_64", target_arch = "x86"),
619        all(target_arch = "aarch64", target_feature = "neon")
620    )))]
621    fn is_alpha_premultiplication_needed(&self) -> bool {
622        use crate::alpha_check::has_non_constant_cap_alpha_rgba16;
623        has_non_constant_cap_alpha_rgba16(self.buffer.as_ref(), self.width, self.stride())
624    }
625
626    #[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
627    fn is_alpha_premultiplication_needed(&self) -> bool {
628        use crate::neon::neon_has_non_constant_cap_alpha_rgba16;
629        neon_has_non_constant_cap_alpha_rgba16(self.buffer.as_ref(), self.width, self.stride())
630    }
631
632    #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
633    fn is_alpha_premultiplication_needed(&self) -> bool {
634        use crate::alpha_check::has_non_constant_cap_alpha_rgba16;
635        #[cfg(feature = "sse")]
636        use crate::sse::sse_has_non_constant_cap_alpha_rgba16;
637        #[cfg(all(target_arch = "x86_64", feature = "avx"))]
638        if std::arch::is_x86_feature_detected!("avx2") {
639            use crate::avx2::avx_has_non_constant_cap_alpha_rgba16;
640            return avx_has_non_constant_cap_alpha_rgba16(
641                self.buffer.as_ref(),
642                self.width,
643                self.stride(),
644            );
645        }
646        #[cfg(feature = "sse")]
647        if std::arch::is_x86_feature_detected!("sse4.1") {
648            return sse_has_non_constant_cap_alpha_rgba16(
649                self.buffer.as_ref(),
650                self.width,
651                self.stride(),
652            );
653        }
654        has_non_constant_cap_alpha_rgba16(self.buffer.as_ref(), self.width, self.stride())
655    }
656}
657
658impl AssociateAlpha<f32, 4> for ImageStore<'_, f32, 4> {
659    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, f32, 4>, pool: &Option<ThreadPool>) {
660        let src_stride = self.stride();
661        let dst_stride = into.stride();
662        let dst = into.buffer.borrow_mut();
663        let src = self.buffer.as_ref();
664        premultiply_alpha_rgba_f32(
665            dst,
666            dst_stride,
667            src,
668            src_stride,
669            self.width,
670            self.height,
671            pool,
672        );
673    }
674
675    fn is_alpha_premultiplication_needed(&self) -> bool {
676        has_non_constant_cap_alpha_rgba_f32(self.buffer.as_ref(), self.width, self.stride())
677    }
678}
679
680#[cfg(feature = "nightly_f16")]
681impl AssociateAlpha<f16, 4> for ImageStore<'_, f16, 4> {
682    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, f16, 4>, pool: &Option<ThreadPool>) {
683        let src_stride = self.stride();
684        let dst_stride = into.stride();
685        let dst = into.buffer.borrow_mut();
686        let src = self.buffer.as_ref();
687        premultiply_alpha_rgba_f16(
688            dst,
689            dst_stride,
690            src,
691            src_stride,
692            self.width,
693            self.height,
694            pool,
695        );
696    }
697
698    fn is_alpha_premultiplication_needed(&self) -> bool {
699        true
700    }
701}
702
703impl UnassociateAlpha<u16, 4> for ImageStoreMut<'_, u16, 4> {
704    fn unpremultiply_alpha(&mut self, pool: &Option<ThreadPool>) {
705        let src_stride = self.stride();
706        let in_place = self.buffer.borrow_mut();
707        unpremultiply_alpha_rgba_u16(
708            in_place,
709            src_stride,
710            self.width,
711            self.height,
712            self.bit_depth,
713            pool,
714        );
715    }
716}
717
718impl UnassociateAlpha<f32, 4> for ImageStoreMut<'_, f32, 4> {
719    fn unpremultiply_alpha(&mut self, pool: &Option<ThreadPool>) {
720        let stride = self.stride();
721        let dst = self.buffer.borrow_mut();
722        unpremultiply_alpha_rgba_f32(dst, stride, self.width, self.height, pool);
723    }
724}
725
726#[cfg(feature = "nightly_f16")]
727impl UnassociateAlpha<f16, 4> for ImageStoreMut<'_, f16, 4> {
728    fn unpremultiply_alpha(&mut self, pool: &Option<ThreadPool>) {
729        let stride = self.stride();
730        let dst = self.buffer.borrow_mut();
731        unpremultiply_alpha_rgba_f16(dst, stride, self.width, self.height, pool);
732    }
733}
734
735pub type Planar8ImageStore<'a> = ImageStore<'a, u8, 1>;
736pub type Planar8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 1>;
737pub type CbCr8ImageStore<'a> = ImageStore<'a, u8, 2>;
738pub type CbCr8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 2>;
739pub type Rgba8ImageStore<'a> = ImageStore<'a, u8, 4>;
740pub type Rgba8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 4>;
741pub type Rgb8ImageStore<'a> = ImageStore<'a, u8, 3>;
742pub type Rgb8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 3>;
743
744pub type Planar16ImageStore<'a> = ImageStore<'a, u16, 1>;
745pub type Planar16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 1>;
746pub type CbCr16ImageStore<'a> = ImageStore<'a, u16, 2>;
747pub type CbCr16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 2>;
748pub type Rgba16ImageStore<'a> = ImageStore<'a, u16, 4>;
749pub type Rgba16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 4>;
750pub type Rgb16ImageStore<'a> = ImageStore<'a, u16, 3>;
751pub type Rgb16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 3>;
752
753#[cfg(feature = "nightly_f16")]
754pub type PlanarF16ImageStore<'a> = ImageStore<'a, f16, 1>;
755#[cfg(feature = "nightly_f16")]
756pub type PlanarF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 1>;
757#[cfg(feature = "nightly_f16")]
758pub type CbCrF16ImageStore<'a> = ImageStore<'a, f16, 2>;
759#[cfg(feature = "nightly_f16")]
760pub type CbCrF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 2>;
761#[cfg(feature = "nightly_f16")]
762pub type RgbaF16ImageStore<'a> = ImageStore<'a, f16, 4>;
763#[cfg(feature = "nightly_f16")]
764pub type RgbaF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 4>;
765#[cfg(feature = "nightly_f16")]
766pub type RgbF16ImageStore<'a> = ImageStore<'a, f16, 3>;
767#[cfg(feature = "nightly_f16")]
768pub type RgbF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 3>;
769
770pub type PlanarF32ImageStore<'a> = ImageStore<'a, f32, 1>;
771pub type PlanarF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 1>;
772pub type CbCrF32ImageStore<'a> = ImageStore<'a, f32, 2>;
773pub type CbCrF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 2>;
774pub type RgbaF32ImageStore<'a> = ImageStore<'a, f32, 4>;
775pub type RgbaF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 4>;
776pub type RgbF32ImageStore<'a> = ImageStore<'a, f32, 3>;
777pub type RgbF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 3>;
778
779#[cfg(test)]
780mod tests {
781    use super::*;
782
783    #[test]
784    fn image_store_alpha_test_rgba8() {
785        let image_size = 256usize;
786        let mut image = vec![0u8; image_size * image_size * 4];
787        image[3 + 150 * 4] = 75;
788        let store = ImageStore::<u8, 4>::from_slice(&image, image_size, image_size).unwrap();
789        let has_alpha = store.is_alpha_premultiplication_needed();
790        assert_eq!(true, has_alpha);
791    }
792
793    #[test]
794    fn check_alpha_not_exists_rgba8() {
795        let image_size = 256usize;
796        let image = vec![255u8; image_size * image_size * 4];
797        let store = ImageStore::<u8, 4>::from_slice(&image, image_size, image_size).unwrap();
798        let has_alpha = store.is_alpha_premultiplication_needed();
799        assert_eq!(false, has_alpha);
800    }
801}