Skip to main content

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_u8::{premultiply_alpha_rgba, unpremultiply_alpha_rgba};
34use crate::alpha_handle_u16::{premultiply_alpha_rgba_u16, unpremultiply_alpha_rgba_u16};
35use crate::support::check_image_size_overflow;
36use crate::validation::{PicScaleBufferMismatch, PicScaleError, try_vec};
37use crate::{ImageSize, WorkloadStrategy};
38#[cfg(feature = "nightly_f16")]
39use core::f16;
40use std::fmt::Debug;
41
42/// Holds an image
43///
44/// # Arguments
45/// `N` - count of channels
46///
47/// # Examples
48/// ImageStore<u8, 4> - represents RGBA
49/// ImageStore<u8, 3> - represents RGB
50/// ImageStore<f32, 3> - represents RGB in f32 and etc
51#[derive(Clone)]
52pub struct ImageStore<'a, T, const N: usize>
53where
54    [T]: ToOwned<Owned = Vec<T>>,
55{
56    pub buffer: std::borrow::Cow<'a, [T]>,
57    /// Channels in the image
58    pub channels: usize,
59    /// Image width
60    pub width: usize,
61    /// Image height
62    pub height: usize,
63    /// Image stride, if stride is zero then it considered to be `width * N`
64    pub stride: usize,
65    /// This is private field, currently used only for u16, will be automatically passed from upper func
66    pub bit_depth: usize,
67}
68
69/// Holds an image
70///
71/// # Arguments
72/// `N` - count of channels
73///
74/// # Examples
75/// ImageStore<u8, 4> - represents RGBA
76/// ImageStore<u8, 3> - represents RGB
77/// ImageStore<f32, 3> - represents RGB in f32 and etc
78pub struct ImageStoreMut<'a, T, const N: usize> {
79    pub buffer: BufferStore<'a, T>,
80    /// Channels in the image
81    pub channels: usize,
82    /// Image width
83    pub width: usize,
84    /// Image height
85    pub height: usize,
86    /// Image stride, if stride is zero then it considered to be `width * N`
87    pub stride: usize,
88    /// Required for `u16` images
89    pub bit_depth: usize,
90}
91
92pub(crate) trait CheckStoreDensity {
93    fn should_have_bit_depth(&self) -> bool;
94}
95
96/// Structure for mutable target buffer
97pub enum BufferStore<'a, T> {
98    Borrowed(&'a mut [T]),
99    Owned(Vec<T>),
100}
101
102impl<T> BufferStore<'_, T> {
103    #[allow(clippy::should_implement_trait)]
104    /// Borrowing immutable slice
105    pub fn borrow(&self) -> &[T] {
106        match self {
107            Self::Borrowed(p_ref) => p_ref,
108            Self::Owned(vec) => vec,
109        }
110    }
111
112    #[allow(clippy::should_implement_trait)]
113    /// Borrowing mutable slice
114    pub fn borrow_mut(&mut self) -> &mut [T] {
115        match self {
116            Self::Borrowed(p_ref) => p_ref,
117            Self::Owned(vec) => vec,
118        }
119    }
120}
121
122impl<'a, T, const N: usize> ImageStore<'a, T, N>
123where
124    T: Clone + Copy + Debug + Default,
125{
126    /// Creates new store
127    pub fn new(
128        slice_ref: Vec<T>,
129        width: usize,
130        height: usize,
131    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
132        let expected_size = width * height * N;
133        if slice_ref.len() < width * height * N {
134            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
135                expected: expected_size,
136                width,
137                height,
138                channels: N,
139                slice_len: slice_ref.len(),
140            }));
141        }
142        Ok(ImageStore::<T, N> {
143            buffer: std::borrow::Cow::Owned(slice_ref),
144            channels: N,
145            width,
146            height,
147            stride: width * N,
148            bit_depth: 0,
149        })
150    }
151
152    /// Borrows immutable slice as new image store
153    pub fn borrow(
154        slice_ref: &'a [T],
155        width: usize,
156        height: usize,
157    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
158        let expected_size = width * height * N;
159        if slice_ref.len() < width * height * N {
160            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
161                expected: expected_size,
162                width,
163                height,
164                channels: N,
165                slice_len: slice_ref.len(),
166            }));
167        }
168        Ok(ImageStore::<T, N> {
169            buffer: std::borrow::Cow::Borrowed(slice_ref),
170            channels: N,
171            width,
172            height,
173            stride: width * N,
174            bit_depth: 0,
175        })
176    }
177
178    /// Allocates new owned image store
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<const N: usize> CheckStoreDensity for ImageStoreMut<'_, i16, N> {
218    fn should_have_bit_depth(&self) -> bool {
219        true
220    }
221}
222
223impl<T, const N: usize> ImageStoreMut<'_, T, N> {
224    pub(crate) fn validate(&self) -> Result<(), PicScaleError> {
225        if self.width == 0 || self.height == 0 {
226            return Err(PicScaleError::ZeroImageDimensions);
227        }
228
229        let valid_size = self.stride() * (self.height - 1) + self.width * N;
230
231        if self.stride() < self.width * N {
232            return Err(PicScaleError::InvalidStride(self.width * N, self.stride));
233        }
234
235        if self.buffer.borrow().len() < valid_size {
236            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
237                expected: valid_size,
238                width: self.width,
239                height: self.height,
240                channels: N,
241                slice_len: self.buffer.borrow().len(),
242            }));
243        }
244        if check_image_size_overflow(self.width, self.height, self.channels) {
245            return Err(PicScaleError::SourceImageIsTooLarge);
246        }
247        Ok(())
248    }
249
250    pub(crate) fn projected(&mut self) -> &mut [T] {
251        let valid_size = self.stride() * (self.height - 1) + self.width * N;
252        &mut self.buffer.borrow_mut()[..valid_size]
253    }
254}
255
256impl<T, const N: usize> ImageStore<'_, T, N>
257where
258    [T]: ToOwned<Owned = Vec<T>>,
259{
260    pub(crate) fn validate(&self) -> Result<(), PicScaleError> {
261        if self.width == 0 || self.height == 0 {
262            return Err(PicScaleError::ZeroImageDimensions);
263        }
264
265        let valid_size = self.stride() * (self.height - 1) + self.width * N;
266
267        if self.stride() < self.width * N {
268            return Err(PicScaleError::InvalidStride(self.width * N, self.stride));
269        }
270
271        if self.buffer.as_ref().len() < valid_size {
272            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
273                expected: valid_size,
274                width: self.width,
275                height: self.height,
276                channels: N,
277                slice_len: self.buffer.as_ref().len(),
278            }));
279        }
280
281        if check_image_size_overflow(self.width, self.height, self.channels) {
282            return Err(PicScaleError::DestinationImageIsTooLarge);
283        }
284
285        Ok(())
286    }
287
288    pub(crate) fn projected(&self) -> &[T] {
289        let valid_size = self.stride() * (self.height - 1) + self.width * N;
290        &self.buffer[..valid_size]
291    }
292}
293
294impl<'a, T, const N: usize> ImageStoreMut<'a, T, N>
295where
296    T: Clone + Copy + Debug + Default,
297{
298    /// Creates new mutable storage from vector
299    ///
300    /// Always sets bit-depth to `0`
301    pub fn new(
302        slice_ref: Vec<T>,
303        width: usize,
304        height: usize,
305    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
306        let expected_size = width * height * N;
307        if slice_ref.len() < width * height * N {
308            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
309                expected: expected_size,
310                width,
311                height,
312                channels: N,
313                slice_len: slice_ref.len(),
314            }));
315        }
316        Ok(ImageStoreMut::<T, N> {
317            buffer: BufferStore::Owned(slice_ref),
318            channels: N,
319            width,
320            height,
321            stride: width * N,
322            bit_depth: 0,
323        })
324    }
325
326    /// Creates new mutable storage from slice
327    ///
328    /// Always sets bit-depth to `0`
329    pub fn borrow(
330        slice_ref: &'a mut [T],
331        width: usize,
332        height: usize,
333    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
334        let expected_size = width * height * N;
335        if slice_ref.len() < width * height * N {
336            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
337                expected: expected_size,
338                width,
339                height,
340                channels: N,
341                slice_len: slice_ref.len(),
342            }));
343        }
344        Ok(ImageStoreMut::<T, N> {
345            buffer: BufferStore::Borrowed(slice_ref),
346            channels: N,
347            width,
348            height,
349            stride: width * N,
350            bit_depth: 0,
351        })
352    }
353
354    /// Allocates new mutable image storage
355    ///
356    /// Always sets bit depth to `0`
357    pub fn alloc(width: usize, height: usize) -> ImageStoreMut<'a, T, N> {
358        let vc = vec![T::default(); width * N * height];
359        ImageStoreMut::<T, N> {
360            buffer: BufferStore::Owned(vc),
361            channels: N,
362            width,
363            height,
364            stride: width * N,
365            bit_depth: 0,
366        }
367    }
368
369    /// Tries to allocate new mutable image storage
370    ///
371    /// Always sets bit depth to `0`
372    pub fn try_alloc(
373        width: usize,
374        height: usize,
375    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
376        let vc = try_vec![T::default(); width * N * height];
377        Ok(ImageStoreMut::<T, N> {
378            buffer: BufferStore::Owned(vc),
379            channels: N,
380            width,
381            height,
382            stride: width * N,
383            bit_depth: 0,
384        })
385    }
386
387    /// Allocates new mutable image storage with required bit-depth
388    pub fn alloc_with_depth(
389        width: usize,
390        height: usize,
391        bit_depth: usize,
392    ) -> ImageStoreMut<'a, T, N> {
393        let vc = vec![T::default(); width * N * height];
394        ImageStoreMut::<T, N> {
395            buffer: BufferStore::Owned(vc),
396            channels: N,
397            width,
398            height,
399            stride: width * N,
400            bit_depth,
401        }
402    }
403
404    /// Tries to allocate new mutable image storage with required bit-depth
405    pub fn try_alloc_with_depth(
406        width: usize,
407        height: usize,
408        bit_depth: usize,
409    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
410        let vc = try_vec![T::default(); width * N * height];
411        Ok(ImageStoreMut::<T, N> {
412            buffer: BufferStore::Owned(vc),
413            channels: N,
414            width,
415            height,
416            stride: width * N,
417            bit_depth,
418        })
419    }
420}
421
422impl<T, const N: usize> ImageStoreMut<'_, T, N> {
423    /// Returns safe stride
424    ///
425    /// If stride set to 0 then returns `width * N`
426    #[inline]
427    pub fn stride(&self) -> usize {
428        if self.stride == 0 {
429            return self.width * N;
430        }
431        self.stride
432    }
433}
434
435impl<'a, T, const N: usize> ImageStore<'a, T, N>
436where
437    [T]: ToOwned<Owned = Vec<T>>,
438{
439    /// Returns safe stride
440    ///
441    /// If stride set to 0 then returns `width * N`
442    #[inline]
443    pub fn stride(&self) -> usize {
444        if self.stride == 0 {
445            return self.width * N;
446        }
447        self.stride
448    }
449
450    pub fn crop(
451        &'a self,
452        x: usize,
453        y: usize,
454        width: usize,
455        height: usize,
456    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
457        self.validate()?;
458        if x + width > self.width || y + height > self.height {
459            return Err(PicScaleError::CropOutOfBounds {
460                x,
461                y,
462                width,
463                height,
464                image_width: self.width,
465                image_height: self.height,
466            });
467        }
468
469        let stride = self.stride();
470        let offset = y * stride + x * N;
471
472        Ok(ImageStore {
473            buffer: std::borrow::Cow::Borrowed(&self.buffer[offset..]),
474            channels: self.channels,
475            width,
476            height,
477            stride,
478            bit_depth: self.bit_depth,
479        })
480    }
481}
482
483impl<'a, T, const N: usize> ImageStore<'a, T, N>
484where
485    T: Clone + Copy + Debug,
486{
487    /// Returns bounded image size
488    pub fn size(&self) -> ImageSize {
489        ImageSize::new(self.width, self.height)
490    }
491
492    /// Returns current image store as immutable slice
493    pub fn as_bytes(&self) -> &[T] {
494        match &self.buffer {
495            std::borrow::Cow::Borrowed(br) => br,
496            std::borrow::Cow::Owned(v) => v.as_ref(),
497        }
498    }
499
500    /// Borrows immutable slice int oa new image store
501    pub fn from_slice(
502        slice_ref: &'a [T],
503        width: usize,
504        height: usize,
505    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
506        let expected_size = width * height * N;
507        if slice_ref.len() < width * height * N {
508            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
509                expected: expected_size,
510                width,
511                height,
512                channels: N,
513                slice_len: slice_ref.len(),
514            }));
515        }
516        Ok(ImageStore::<T, N> {
517            buffer: std::borrow::Cow::Borrowed(slice_ref),
518            channels: N,
519            width,
520            height,
521            stride: width * N,
522            bit_depth: 0,
523        })
524    }
525
526    /// Deep copy immutable image store into a new immutable store
527    pub fn copied<'b>(&self) -> ImageStore<'b, T, N> {
528        ImageStore::<T, N> {
529            buffer: std::borrow::Cow::Owned(self.buffer.as_ref().to_vec()),
530            channels: N,
531            width: self.width,
532            height: self.height,
533            stride: self.width * N,
534            bit_depth: self.bit_depth,
535        }
536    }
537
538    /// Deep copy immutable image into mutable
539    pub fn copied_to_mut(&self, into: &mut ImageStoreMut<T, N>) {
540        let into_stride = into.stride();
541        let dst_buffer = into.projected();
542        for (src_row, dst_row) in self
543            .projected()
544            .chunks(self.stride())
545            .zip(dst_buffer.chunks_mut(into_stride))
546        {
547            for (&src, dst) in src_row.iter().zip(dst_row.iter_mut()) {
548                *dst = src;
549            }
550        }
551    }
552}
553
554impl<'a, T, const N: usize> ImageStoreMut<'a, T, N> {
555    /// Returns bounded image size
556    pub fn size(&self) -> ImageSize {
557        ImageSize::new(self.width, self.height)
558    }
559
560    /// Returns current image as immutable slice
561    pub fn as_bytes(&self) -> &[T] {
562        match &self.buffer {
563            BufferStore::Borrowed(p) => p,
564            BufferStore::Owned(v) => v,
565        }
566    }
567
568    /// Borrows mutable slice as new image store
569    pub fn from_slice(
570        slice_ref: &'a mut [T],
571        width: usize,
572        height: usize,
573    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
574        let expected_size = width * height * N;
575        if slice_ref.len() < width * height * N {
576            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
577                expected: expected_size,
578                width,
579                height,
580                channels: N,
581                slice_len: slice_ref.len(),
582            }));
583        }
584        Ok(ImageStoreMut::<T, N> {
585            buffer: BufferStore::Borrowed(slice_ref),
586            channels: N,
587            width,
588            height,
589            stride: width * N,
590            bit_depth: 0,
591        })
592    }
593}
594
595impl<'a, T, const N: usize> ImageStoreMut<'a, T, N>
596where
597    T: Clone,
598{
599    /// Performs deep copy into a new mutable image
600    pub fn copied<'b>(&self) -> ImageStoreMut<'b, T, N> {
601        ImageStoreMut::<T, N> {
602            buffer: BufferStore::Owned(self.buffer.borrow().to_vec()),
603            channels: N,
604            width: self.width,
605            height: self.height,
606            stride: self.width * N,
607            bit_depth: self.bit_depth,
608        }
609    }
610
611    /// Performs deep copy into a new immutable image
612    pub fn to_immutable(&self) -> ImageStore<'_, T, N> {
613        ImageStore::<T, N> {
614            buffer: std::borrow::Cow::Borrowed(self.buffer.borrow()),
615            channels: N,
616            width: self.width,
617            height: self.height,
618            stride: self.width * N,
619            bit_depth: self.bit_depth,
620        }
621    }
622
623    pub fn crop(
624        &'a mut self,
625        x: usize,
626        y: usize,
627        width: usize,
628        height: usize,
629    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
630        self.validate()?;
631        if x + width > self.width || y + height > self.height {
632            return Err(PicScaleError::CropOutOfBounds {
633                x,
634                y,
635                width,
636                height,
637                image_width: self.width,
638                image_height: self.height,
639            });
640        }
641
642        let stride = self.stride();
643        let offset = y * stride + x * N;
644
645        Ok(ImageStoreMut {
646            buffer: BufferStore::Borrowed(&mut self.buffer.borrow_mut()[offset..]),
647            channels: self.channels,
648            width,
649            height,
650            stride,
651            bit_depth: self.bit_depth,
652        })
653    }
654}
655
656pub(crate) trait AssociateAlpha<T: Clone + Copy + Debug, const N: usize> {
657    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, T, N>, pool: &novtb::ThreadPool);
658    fn is_alpha_premultiplication_needed(&self) -> bool;
659}
660
661pub(crate) trait UnassociateAlpha<T: Clone + Copy + Debug, const N: usize> {
662    fn unpremultiply_alpha(
663        &mut self,
664        pool: &novtb::ThreadPool,
665        workload_strategy: WorkloadStrategy,
666    );
667}
668
669impl AssociateAlpha<u8, 2> for ImageStore<'_, u8, 2> {
670    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u8, 2>, pool: &novtb::ThreadPool) {
671        let dst_stride = into.stride();
672        let dst = into.projected();
673        let src = self.projected();
674        use crate::alpha_handle_u8::premultiply_alpha_gray_alpha;
675        premultiply_alpha_gray_alpha(
676            dst,
677            dst_stride,
678            src,
679            self.width,
680            self.height,
681            self.stride(),
682            pool,
683        );
684    }
685
686    fn is_alpha_premultiplication_needed(&self) -> bool {
687        use crate::alpha_check::has_non_constant_cap_alpha_gray_alpha8;
688        has_non_constant_cap_alpha_gray_alpha8(self.projected(), self.width, self.stride())
689    }
690}
691
692impl AssociateAlpha<u16, 2> for ImageStore<'_, u16, 2> {
693    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u16, 2>, pool: &novtb::ThreadPool) {
694        let dst_stride = into.stride();
695        let dst = into.projected();
696        let src = self.projected();
697        let bit_depth = self.bit_depth;
698        use crate::alpha_handle_u16::premultiply_alpha_gray_alpha_u16;
699        premultiply_alpha_gray_alpha_u16(
700            dst,
701            dst_stride,
702            src,
703            self.width,
704            self.height,
705            self.stride(),
706            bit_depth,
707            pool,
708        );
709    }
710
711    fn is_alpha_premultiplication_needed(&self) -> bool {
712        use crate::alpha_check::has_non_constant_cap_alpha_gray_alpha16;
713        has_non_constant_cap_alpha_gray_alpha16(self.projected(), self.width, self.stride())
714    }
715}
716
717impl AssociateAlpha<f32, 2> for ImageStore<'_, f32, 2> {
718    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, f32, 2>, pool: &novtb::ThreadPool) {
719        let dst_stride = into.stride();
720        let dst = into.projected();
721        let src = self.projected();
722        use crate::alpha_handle_f32::premultiply_alpha_gray_alpha_f32;
723        premultiply_alpha_gray_alpha_f32(
724            dst,
725            dst_stride,
726            src,
727            self.stride(),
728            self.width,
729            self.height,
730            pool,
731        );
732    }
733
734    fn is_alpha_premultiplication_needed(&self) -> bool {
735        use crate::alpha_check::has_non_constant_cap_alpha_gray_alpha_f32;
736        has_non_constant_cap_alpha_gray_alpha_f32(self.projected(), self.width, self.stride())
737    }
738}
739
740impl AssociateAlpha<u8, 4> for ImageStore<'_, u8, 4> {
741    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u8, 4>, pool: &novtb::ThreadPool) {
742        let dst_stride = into.stride();
743        let dst = into.projected();
744        let src = self.projected();
745        premultiply_alpha_rgba(
746            dst,
747            dst_stride,
748            src,
749            self.width,
750            self.height,
751            self.stride(),
752            pool,
753        );
754    }
755
756    #[cfg(not(any(
757        any(target_arch = "x86_64", target_arch = "x86"),
758        all(target_arch = "aarch64", feature = "neon")
759    )))]
760    fn is_alpha_premultiplication_needed(&self) -> bool {
761        use crate::alpha_check::has_non_constant_cap_alpha_rgba8;
762        has_non_constant_cap_alpha_rgba8(self.projected(), self.width, self.stride())
763    }
764
765    #[cfg(all(target_arch = "aarch64", feature = "neon"))]
766    fn is_alpha_premultiplication_needed(&self) -> bool {
767        use crate::neon::neon_has_non_constant_cap_alpha_rgba8;
768        neon_has_non_constant_cap_alpha_rgba8(self.projected(), self.width, self.stride())
769    }
770
771    #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
772    fn is_alpha_premultiplication_needed(&self) -> bool {
773        use crate::alpha_check::has_non_constant_cap_alpha_rgba8;
774        #[cfg(feature = "sse")]
775        use crate::sse::sse_has_non_constant_cap_alpha_rgba8;
776        #[cfg(all(target_arch = "x86_64", feature = "avx512"))]
777        if std::arch::is_x86_feature_detected!("avx512bw") {
778            use crate::avx512::avx512_has_non_constant_cap_alpha_rgba8;
779            return avx512_has_non_constant_cap_alpha_rgba8(
780                self.projected(),
781                self.width,
782                self.stride(),
783            );
784        }
785        #[cfg(all(target_arch = "x86_64", feature = "avx"))]
786        if std::arch::is_x86_feature_detected!("avx2") {
787            use crate::avx2::avx_has_non_constant_cap_alpha_rgba8;
788            return avx_has_non_constant_cap_alpha_rgba8(
789                self.projected(),
790                self.width,
791                self.stride(),
792            );
793        }
794        #[cfg(feature = "sse")]
795        if std::arch::is_x86_feature_detected!("sse4.1") {
796            return sse_has_non_constant_cap_alpha_rgba8(
797                self.projected(),
798                self.width,
799                self.stride(),
800            );
801        }
802        has_non_constant_cap_alpha_rgba8(self.projected(), self.width, self.stride())
803    }
804}
805
806impl UnassociateAlpha<u8, 4> for ImageStoreMut<'_, u8, 4> {
807    fn unpremultiply_alpha(
808        &mut self,
809        pool: &novtb::ThreadPool,
810        workload_strategy: WorkloadStrategy,
811    ) {
812        let src_stride = self.stride();
813        let width = self.width;
814        let height = self.height;
815        let dst = self.projected();
816        unpremultiply_alpha_rgba(dst, width, height, src_stride, pool, workload_strategy);
817    }
818}
819
820impl UnassociateAlpha<u8, 2> for ImageStoreMut<'_, u8, 2> {
821    fn unpremultiply_alpha(
822        &mut self,
823        pool: &novtb::ThreadPool,
824        workload_strategy: WorkloadStrategy,
825    ) {
826        let src_stride = self.stride();
827        let width = self.width;
828        let height = self.height;
829        let dst = self.projected();
830        use crate::alpha_handle_u8::unpremultiply_alpha_gray_alpha;
831        unpremultiply_alpha_gray_alpha(dst, width, height, src_stride, pool, workload_strategy);
832    }
833}
834
835impl UnassociateAlpha<f32, 2> for ImageStoreMut<'_, f32, 2> {
836    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
837        let src_stride = self.stride();
838        let width = self.width;
839        let height = self.height;
840        let dst = self.projected();
841        use crate::alpha_handle_f32::unpremultiply_alpha_gray_alpha_f32;
842        unpremultiply_alpha_gray_alpha_f32(dst, src_stride, width, height, pool);
843    }
844}
845
846impl UnassociateAlpha<u16, 2> for ImageStoreMut<'_, u16, 2> {
847    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
848        let src_stride = self.stride();
849        let width = self.width;
850        let height = self.height;
851        let bit_depth = self.bit_depth;
852        let dst = self.projected();
853        use crate::alpha_handle_u16::unpremultiply_alpha_gray_alpha_u16;
854        unpremultiply_alpha_gray_alpha_u16(dst, src_stride, width, height, bit_depth, pool);
855    }
856}
857
858impl AssociateAlpha<u16, 4> for ImageStore<'_, u16, 4> {
859    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u16, 4>, pool: &novtb::ThreadPool) {
860        let dst_stride = into.stride();
861        let bit_depth = into.bit_depth;
862        let dst = into.projected();
863        let src = self.projected();
864        premultiply_alpha_rgba_u16(
865            dst,
866            dst_stride,
867            src,
868            self.width,
869            self.height,
870            self.stride(),
871            bit_depth,
872            pool,
873        );
874    }
875
876    #[cfg(not(any(
877        any(target_arch = "x86_64", target_arch = "x86"),
878        all(target_arch = "aarch64", feature = "neon")
879    )))]
880    fn is_alpha_premultiplication_needed(&self) -> bool {
881        use crate::alpha_check::has_non_constant_cap_alpha_rgba16;
882        has_non_constant_cap_alpha_rgba16(self.projected(), self.width, self.stride())
883    }
884
885    #[cfg(all(target_arch = "aarch64", feature = "neon"))]
886    fn is_alpha_premultiplication_needed(&self) -> bool {
887        use crate::neon::neon_has_non_constant_cap_alpha_rgba16;
888        neon_has_non_constant_cap_alpha_rgba16(self.projected(), self.width, self.stride())
889    }
890
891    #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
892    fn is_alpha_premultiplication_needed(&self) -> bool {
893        use crate::alpha_check::has_non_constant_cap_alpha_rgba16;
894        #[cfg(feature = "sse")]
895        use crate::sse::sse_has_non_constant_cap_alpha_rgba16;
896        #[cfg(all(target_arch = "x86_64", feature = "avx"))]
897        if std::arch::is_x86_feature_detected!("avx2") {
898            use crate::avx2::avx_has_non_constant_cap_alpha_rgba16;
899            return avx_has_non_constant_cap_alpha_rgba16(
900                self.projected(),
901                self.width,
902                self.stride(),
903            );
904        }
905        #[cfg(feature = "sse")]
906        if std::arch::is_x86_feature_detected!("sse4.1") {
907            return sse_has_non_constant_cap_alpha_rgba16(
908                self.projected(),
909                self.width,
910                self.stride(),
911            );
912        }
913        has_non_constant_cap_alpha_rgba16(self.projected(), self.width, self.stride())
914    }
915}
916
917impl AssociateAlpha<f32, 4> for ImageStore<'_, f32, 4> {
918    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, f32, 4>, pool: &novtb::ThreadPool) {
919        let src_stride = self.stride();
920        let dst_stride = into.stride();
921        let width = self.width;
922        let height = self.height;
923        let dst = into.projected();
924        let src = self.projected();
925        premultiply_alpha_rgba_f32(dst, dst_stride, src, src_stride, width, height, pool);
926    }
927
928    fn is_alpha_premultiplication_needed(&self) -> bool {
929        has_non_constant_cap_alpha_rgba_f32(self.projected(), self.width, self.stride())
930    }
931}
932
933#[cfg(feature = "nightly_f16")]
934impl AssociateAlpha<f16, 4> for ImageStore<'_, f16, 4> {
935    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, f16, 4>, pool: &novtb::ThreadPool) {
936        let src_stride = self.stride();
937        let dst_stride = into.stride();
938        let width = self.width;
939        let height = self.height;
940        let dst = into.projected();
941        let src = self.projected();
942        premultiply_alpha_rgba_f16(dst, dst_stride, src, src_stride, width, height, pool);
943    }
944
945    fn is_alpha_premultiplication_needed(&self) -> bool {
946        true
947    }
948}
949
950impl UnassociateAlpha<u16, 4> for ImageStoreMut<'_, u16, 4> {
951    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
952        let src_stride = self.stride();
953        let width = self.width;
954        let height = self.height;
955        let bit_depth = self.bit_depth;
956        let in_place = self.projected();
957        unpremultiply_alpha_rgba_u16(in_place, src_stride, width, height, bit_depth, pool);
958    }
959}
960
961impl UnassociateAlpha<f32, 4> for ImageStoreMut<'_, f32, 4> {
962    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
963        let stride = self.stride();
964        let width = self.width;
965        let height = self.height;
966        let dst = self.projected();
967        unpremultiply_alpha_rgba_f32(dst, stride, width, height, pool);
968    }
969}
970
971#[cfg(feature = "nightly_f16")]
972impl UnassociateAlpha<f16, 4> for ImageStoreMut<'_, f16, 4> {
973    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
974        let stride = self.stride();
975        let width = self.width;
976        let height = self.height;
977        let dst = self.projected();
978        unpremultiply_alpha_rgba_f16(dst, stride, width, height, pool);
979    }
980}
981
982pub type Planar8ImageStore<'a> = ImageStore<'a, u8, 1>;
983pub type Planar8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 1>;
984pub type CbCr8ImageStore<'a> = ImageStore<'a, u8, 2>;
985pub type CbCr8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 2>;
986pub type GrayAlpha8ImageStore<'a> = ImageStore<'a, u8, 2>;
987pub type GrayAlpha8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 2>;
988pub type Rgba8ImageStore<'a> = ImageStore<'a, u8, 4>;
989pub type Rgba8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 4>;
990pub type Rgb8ImageStore<'a> = ImageStore<'a, u8, 3>;
991pub type Rgb8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 3>;
992
993pub type PlanarS16ImageStore<'a> = ImageStore<'a, i16, 1>;
994pub type PlanarS16ImageStoreMut<'a> = ImageStoreMut<'a, i16, 1>;
995pub type Planar16ImageStore<'a> = ImageStore<'a, u16, 1>;
996pub type Planar16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 1>;
997pub type CbCr16ImageStore<'a> = ImageStore<'a, u16, 2>;
998pub type CbCr16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 2>;
999pub type GrayAlpha16ImageStore<'a> = ImageStore<'a, u16, 2>;
1000pub type GrayAlpha16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 2>;
1001pub type Rgba16ImageStore<'a> = ImageStore<'a, u16, 4>;
1002pub type Rgba16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 4>;
1003pub type Rgb16ImageStore<'a> = ImageStore<'a, u16, 3>;
1004pub type Rgb16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 3>;
1005
1006#[cfg(feature = "nightly_f16")]
1007pub type PlanarF16ImageStore<'a> = ImageStore<'a, f16, 1>;
1008#[cfg(feature = "nightly_f16")]
1009pub type PlanarF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 1>;
1010#[cfg(feature = "nightly_f16")]
1011pub type CbCrF16ImageStore<'a> = ImageStore<'a, f16, 2>;
1012#[cfg(feature = "nightly_f16")]
1013pub type CbCrF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 2>;
1014#[cfg(feature = "nightly_f16")]
1015pub type RgbaF16ImageStore<'a> = ImageStore<'a, f16, 4>;
1016#[cfg(feature = "nightly_f16")]
1017pub type RgbaF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 4>;
1018#[cfg(feature = "nightly_f16")]
1019pub type RgbF16ImageStore<'a> = ImageStore<'a, f16, 3>;
1020#[cfg(feature = "nightly_f16")]
1021pub type RgbF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 3>;
1022
1023pub type PlanarF32ImageStore<'a> = ImageStore<'a, f32, 1>;
1024pub type PlanarF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 1>;
1025pub type CbCrF32ImageStore<'a> = ImageStore<'a, f32, 2>;
1026pub type CbCrF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 2>;
1027pub type GrayAlphaF32ImageStore<'a> = ImageStore<'a, f32, 2>;
1028pub type GrayAlphaF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 2>;
1029pub type RgbaF32ImageStore<'a> = ImageStore<'a, f32, 4>;
1030pub type RgbaF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 4>;
1031pub type RgbF32ImageStore<'a> = ImageStore<'a, f32, 3>;
1032pub type RgbF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 3>;
1033
1034#[cfg(test)]
1035mod tests {
1036    use super::*;
1037
1038    #[test]
1039    fn image_store_alpha_test_rgba8() {
1040        let image_size = 256usize;
1041        let mut image = vec![0u8; image_size * image_size * 4];
1042        image[3 + 150 * 4] = 75;
1043        let store = ImageStore::<u8, 4>::from_slice(&image, image_size, image_size).unwrap();
1044        let has_alpha = store.is_alpha_premultiplication_needed();
1045        assert_eq!(true, has_alpha);
1046    }
1047
1048    #[test]
1049    fn check_alpha_not_exists_rgba8() {
1050        let image_size = 256usize;
1051        let image = vec![255u8; image_size * image_size * 4];
1052        let store = ImageStore::<u8, 4>::from_slice(&image, image_size, image_size).unwrap();
1053        let has_alpha = store.is_alpha_premultiplication_needed();
1054        assert_eq!(false, has_alpha);
1055    }
1056}