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, check_image_size_overflow_with_stride};
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        if check_image_size_overflow(
230            self.width,
231            self.height,
232            self.channels,
233            size_of::<T>() as isize,
234        ) {
235            return Err(PicScaleError::SourceImageIsTooLarge);
236        }
237
238        if check_image_size_overflow_with_stride(
239            self.width,
240            self.height,
241            self.stride(),
242            self.channels,
243            size_of::<T>() as isize,
244        ) {
245            return Err(PicScaleError::SourceImageIsTooLarge);
246        }
247
248        let valid_size = self.stride() * (self.height - 1) + self.width * N;
249
250        if self.stride() < self.width * N {
251            return Err(PicScaleError::InvalidStride(self.width * N, self.stride));
252        }
253
254        if self.buffer.borrow().len() < valid_size {
255            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
256                expected: valid_size,
257                width: self.width,
258                height: self.height,
259                channels: N,
260                slice_len: self.buffer.borrow().len(),
261            }));
262        }
263        Ok(())
264    }
265
266    pub(crate) fn projected(&mut self) -> &mut [T] {
267        let valid_size = self.stride() * (self.height - 1) + self.width * N;
268        &mut self.buffer.borrow_mut()[..valid_size]
269    }
270}
271
272impl<T, const N: usize> ImageStore<'_, T, N>
273where
274    [T]: ToOwned<Owned = Vec<T>>,
275{
276    pub(crate) fn validate(&self) -> Result<(), PicScaleError> {
277        if self.width == 0 || self.height == 0 {
278            return Err(PicScaleError::ZeroImageDimensions);
279        }
280
281        if check_image_size_overflow(
282            self.width,
283            self.height,
284            self.channels,
285            size_of::<T>() as isize,
286        ) {
287            return Err(PicScaleError::DestinationImageIsTooLarge);
288        }
289
290        if check_image_size_overflow_with_stride(
291            self.width,
292            self.height,
293            self.stride(),
294            self.channels,
295            size_of::<T>() as isize,
296        ) {
297            return Err(PicScaleError::DestinationImageIsTooLarge);
298        }
299
300        let valid_size = self.stride() * (self.height - 1) + self.width * N;
301
302        if self.stride() < self.width * N {
303            return Err(PicScaleError::InvalidStride(self.width * N, self.stride));
304        }
305
306        if self.buffer.as_ref().len() < valid_size {
307            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
308                expected: valid_size,
309                width: self.width,
310                height: self.height,
311                channels: N,
312                slice_len: self.buffer.as_ref().len(),
313            }));
314        }
315
316        Ok(())
317    }
318
319    pub(crate) fn projected(&self) -> &[T] {
320        let valid_size = self.stride() * (self.height - 1) + self.width * N;
321        &self.buffer[..valid_size]
322    }
323}
324
325impl<'a, T, const N: usize> ImageStoreMut<'a, T, N>
326where
327    T: Clone + Copy + Debug + Default,
328{
329    /// Creates new mutable storage from vector
330    ///
331    /// Always sets bit-depth to `0`
332    pub fn new(
333        slice_ref: Vec<T>,
334        width: usize,
335        height: usize,
336    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
337        let expected_size = width * height * N;
338        if slice_ref.len() < width * height * N {
339            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
340                expected: expected_size,
341                width,
342                height,
343                channels: N,
344                slice_len: slice_ref.len(),
345            }));
346        }
347        Ok(ImageStoreMut::<T, N> {
348            buffer: BufferStore::Owned(slice_ref),
349            channels: N,
350            width,
351            height,
352            stride: width * N,
353            bit_depth: 0,
354        })
355    }
356
357    /// Creates new mutable storage from slice
358    ///
359    /// Always sets bit-depth to `0`
360    pub fn borrow(
361        slice_ref: &'a mut [T],
362        width: usize,
363        height: usize,
364    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
365        let expected_size = width * height * N;
366        if slice_ref.len() < width * height * N {
367            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
368                expected: expected_size,
369                width,
370                height,
371                channels: N,
372                slice_len: slice_ref.len(),
373            }));
374        }
375        Ok(ImageStoreMut::<T, N> {
376            buffer: BufferStore::Borrowed(slice_ref),
377            channels: N,
378            width,
379            height,
380            stride: width * N,
381            bit_depth: 0,
382        })
383    }
384
385    /// Allocates new mutable image storage
386    ///
387    /// Always sets bit depth to `0`
388    pub fn alloc(width: usize, height: usize) -> ImageStoreMut<'a, T, N> {
389        let vc = vec![T::default(); width * N * height];
390        ImageStoreMut::<T, N> {
391            buffer: BufferStore::Owned(vc),
392            channels: N,
393            width,
394            height,
395            stride: width * N,
396            bit_depth: 0,
397        }
398    }
399
400    /// Tries to allocate new mutable image storage
401    ///
402    /// Always sets bit depth to `0`
403    pub fn try_alloc(
404        width: usize,
405        height: usize,
406    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
407        let vc = try_vec![T::default(); width * N * height];
408        Ok(ImageStoreMut::<T, N> {
409            buffer: BufferStore::Owned(vc),
410            channels: N,
411            width,
412            height,
413            stride: width * N,
414            bit_depth: 0,
415        })
416    }
417
418    /// Allocates new mutable image storage with required bit-depth
419    pub fn alloc_with_depth(
420        width: usize,
421        height: usize,
422        bit_depth: usize,
423    ) -> ImageStoreMut<'a, T, N> {
424        let vc = vec![T::default(); width * N * height];
425        ImageStoreMut::<T, N> {
426            buffer: BufferStore::Owned(vc),
427            channels: N,
428            width,
429            height,
430            stride: width * N,
431            bit_depth,
432        }
433    }
434
435    /// Tries to allocate new mutable image storage with required bit-depth
436    pub fn try_alloc_with_depth(
437        width: usize,
438        height: usize,
439        bit_depth: usize,
440    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
441        let vc = try_vec![T::default(); width * N * height];
442        Ok(ImageStoreMut::<T, N> {
443            buffer: BufferStore::Owned(vc),
444            channels: N,
445            width,
446            height,
447            stride: width * N,
448            bit_depth,
449        })
450    }
451}
452
453impl<T, const N: usize> ImageStoreMut<'_, T, N> {
454    /// Returns safe stride
455    ///
456    /// If stride set to 0 then returns `width * N`
457    #[inline]
458    pub fn stride(&self) -> usize {
459        if self.stride == 0 {
460            return self.width * N;
461        }
462        self.stride
463    }
464}
465
466impl<'a, T, const N: usize> ImageStore<'a, T, N>
467where
468    [T]: ToOwned<Owned = Vec<T>>,
469{
470    /// Returns safe stride
471    ///
472    /// If stride set to 0 then returns `width * N`
473    #[inline]
474    pub fn stride(&self) -> usize {
475        if self.stride == 0 {
476            return self.width * N;
477        }
478        self.stride
479    }
480
481    pub fn crop(
482        &'a self,
483        x: usize,
484        y: usize,
485        width: usize,
486        height: usize,
487    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
488        self.validate()?;
489        if x + width > self.width || y + height > self.height {
490            return Err(PicScaleError::CropOutOfBounds {
491                x,
492                y,
493                width,
494                height,
495                image_width: self.width,
496                image_height: self.height,
497            });
498        }
499
500        let stride = self.stride();
501        let offset = y * stride + x * N;
502
503        Ok(ImageStore {
504            buffer: std::borrow::Cow::Borrowed(&self.buffer[offset..]),
505            channels: self.channels,
506            width,
507            height,
508            stride,
509            bit_depth: self.bit_depth,
510        })
511    }
512}
513
514impl<'a, T: Default + Clone + Copy, const N: usize> ImageStore<'a, T, N>
515where
516    [T]: ToOwned<Owned = Vec<T>>,
517{
518    pub fn crop_with_copy(
519        &self,
520        x: usize,
521        y: usize,
522        width: usize,
523        height: usize,
524    ) -> Result<ImageStore<'static, T, N>, PicScaleError> {
525        self.validate()?;
526        if x + width > self.width || y + height > self.height {
527            return Err(PicScaleError::CropOutOfBounds {
528                x,
529                y,
530                width,
531                height,
532                image_width: self.width,
533                image_height: self.height,
534            });
535        }
536
537        let src_stride = self.stride();
538        let dst_stride = width * N;
539        let mut buffer = try_vec![T::default(); height * dst_stride];
540
541        buffer
542            .chunks_exact_mut(dst_stride)
543            .zip(self.buffer[y * src_stride + x * N..].chunks_exact(src_stride))
544            .for_each(|(dst, src)| dst.copy_from_slice(&src[..dst_stride]));
545
546        Ok(ImageStore {
547            buffer: std::borrow::Cow::Owned(buffer),
548            channels: self.channels,
549            width,
550            height,
551            stride: dst_stride,
552            bit_depth: self.bit_depth,
553        })
554    }
555}
556
557impl<'a, T, const N: usize> ImageStore<'a, T, N>
558where
559    T: Clone + Copy + Debug,
560{
561    /// Returns bounded image size
562    pub fn size(&self) -> ImageSize {
563        ImageSize::new(self.width, self.height)
564    }
565
566    /// Returns current image store as immutable slice
567    pub fn as_bytes(&self) -> &[T] {
568        match &self.buffer {
569            std::borrow::Cow::Borrowed(br) => br,
570            std::borrow::Cow::Owned(v) => v.as_ref(),
571        }
572    }
573
574    /// Borrows immutable slice int oa new image store
575    pub fn from_slice(
576        slice_ref: &'a [T],
577        width: usize,
578        height: usize,
579    ) -> Result<ImageStore<'a, T, N>, PicScaleError> {
580        let expected_size = width * height * N;
581        if slice_ref.len() < width * height * N {
582            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
583                expected: expected_size,
584                width,
585                height,
586                channels: N,
587                slice_len: slice_ref.len(),
588            }));
589        }
590        Ok(ImageStore::<T, N> {
591            buffer: std::borrow::Cow::Borrowed(slice_ref),
592            channels: N,
593            width,
594            height,
595            stride: width * N,
596            bit_depth: 0,
597        })
598    }
599
600    /// Deep copy immutable image store into a new immutable store
601    pub fn copied<'b>(&self) -> ImageStore<'b, T, N> {
602        ImageStore::<T, N> {
603            buffer: std::borrow::Cow::Owned(self.buffer.as_ref().to_vec()),
604            channels: N,
605            width: self.width,
606            height: self.height,
607            stride: self.width * N,
608            bit_depth: self.bit_depth,
609        }
610    }
611
612    /// Deep copy immutable image into mutable
613    pub fn copied_to_mut(&self, into: &mut ImageStoreMut<T, N>) {
614        let into_stride = into.stride();
615        let dst_buffer = into.projected();
616        for (src_row, dst_row) in self
617            .projected()
618            .chunks(self.stride())
619            .zip(dst_buffer.chunks_mut(into_stride))
620        {
621            for (&src, dst) in src_row.iter().zip(dst_row.iter_mut()) {
622                *dst = src;
623            }
624        }
625    }
626}
627
628impl<'a, T, const N: usize> ImageStoreMut<'a, T, N> {
629    /// Returns bounded image size
630    pub fn size(&self) -> ImageSize {
631        ImageSize::new(self.width, self.height)
632    }
633
634    /// Returns current image as immutable slice
635    pub fn as_bytes(&self) -> &[T] {
636        match &self.buffer {
637            BufferStore::Borrowed(p) => p,
638            BufferStore::Owned(v) => v,
639        }
640    }
641
642    /// Borrows mutable slice as new image store
643    pub fn from_slice(
644        slice_ref: &'a mut [T],
645        width: usize,
646        height: usize,
647    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
648        let expected_size = width * height * N;
649        if slice_ref.len() < width * height * N {
650            return Err(PicScaleError::BufferMismatch(PicScaleBufferMismatch {
651                expected: expected_size,
652                width,
653                height,
654                channels: N,
655                slice_len: slice_ref.len(),
656            }));
657        }
658        Ok(ImageStoreMut::<T, N> {
659            buffer: BufferStore::Borrowed(slice_ref),
660            channels: N,
661            width,
662            height,
663            stride: width * N,
664            bit_depth: 0,
665        })
666    }
667}
668
669impl<'a, T, const N: usize> ImageStoreMut<'a, T, N>
670where
671    T: Clone,
672{
673    /// Performs deep copy into a new mutable image
674    pub fn copied<'b>(&self) -> ImageStoreMut<'b, T, N> {
675        ImageStoreMut::<T, N> {
676            buffer: BufferStore::Owned(self.buffer.borrow().to_vec()),
677            channels: N,
678            width: self.width,
679            height: self.height,
680            stride: self.width * N,
681            bit_depth: self.bit_depth,
682        }
683    }
684
685    /// Performs deep copy into a new immutable image
686    pub fn to_immutable(&self) -> ImageStore<'_, T, N> {
687        ImageStore::<T, N> {
688            buffer: std::borrow::Cow::Borrowed(self.buffer.borrow()),
689            channels: N,
690            width: self.width,
691            height: self.height,
692            stride: self.width * N,
693            bit_depth: self.bit_depth,
694        }
695    }
696
697    pub fn crop(
698        &'a mut self,
699        x: usize,
700        y: usize,
701        width: usize,
702        height: usize,
703    ) -> Result<ImageStoreMut<'a, T, N>, PicScaleError> {
704        self.validate()?;
705        if x + width > self.width || y + height > self.height {
706            return Err(PicScaleError::CropOutOfBounds {
707                x,
708                y,
709                width,
710                height,
711                image_width: self.width,
712                image_height: self.height,
713            });
714        }
715
716        let stride = self.stride();
717        let offset = y * stride + x * N;
718
719        Ok(ImageStoreMut {
720            buffer: BufferStore::Borrowed(&mut self.buffer.borrow_mut()[offset..]),
721            channels: self.channels,
722            width,
723            height,
724            stride,
725            bit_depth: self.bit_depth,
726        })
727    }
728}
729
730impl<'a, T: Clone + Default + Copy, const N: usize> ImageStoreMut<'a, T, N> {
731    pub fn crop_with_copy(
732        &self,
733        x: usize,
734        y: usize,
735        width: usize,
736        height: usize,
737    ) -> Result<ImageStoreMut<'static, T, N>, PicScaleError> {
738        self.validate()?;
739        if x + width > self.width || y + height > self.height {
740            return Err(PicScaleError::CropOutOfBounds {
741                x,
742                y,
743                width,
744                height,
745                image_width: self.width,
746                image_height: self.height,
747            });
748        }
749
750        let src_stride = self.stride();
751        let dst_stride = width * N;
752        let mut buffer = try_vec![T::default(); height * dst_stride];
753
754        buffer
755            .chunks_exact_mut(dst_stride)
756            .zip(self.buffer.borrow()[y * src_stride + x * N..].chunks_exact(src_stride))
757            .for_each(|(dst, src)| dst.copy_from_slice(&src[..dst_stride]));
758
759        Ok(ImageStoreMut {
760            buffer: BufferStore::Owned(buffer),
761            channels: self.channels,
762            width,
763            height,
764            stride: dst_stride,
765            bit_depth: self.bit_depth,
766        })
767    }
768}
769
770pub(crate) trait AssociateAlpha<T: Clone + Copy + Debug, const N: usize> {
771    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, T, N>, pool: &novtb::ThreadPool);
772    fn is_alpha_premultiplication_needed(&self) -> bool;
773}
774
775pub(crate) trait UnassociateAlpha<T: Clone + Copy + Debug, const N: usize> {
776    fn unpremultiply_alpha(
777        &mut self,
778        pool: &novtb::ThreadPool,
779        workload_strategy: WorkloadStrategy,
780    );
781}
782
783impl AssociateAlpha<u8, 2> for ImageStore<'_, u8, 2> {
784    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u8, 2>, pool: &novtb::ThreadPool) {
785        let dst_stride = into.stride();
786        let dst = into.projected();
787        let src = self.projected();
788        use crate::alpha_handle_u8::premultiply_alpha_gray_alpha;
789        premultiply_alpha_gray_alpha(
790            dst,
791            dst_stride,
792            src,
793            self.width,
794            self.height,
795            self.stride(),
796            pool,
797        );
798    }
799
800    fn is_alpha_premultiplication_needed(&self) -> bool {
801        use crate::alpha_check::has_non_constant_cap_alpha_gray_alpha8;
802        has_non_constant_cap_alpha_gray_alpha8(self.projected(), self.width, self.stride())
803    }
804}
805
806impl AssociateAlpha<u16, 2> for ImageStore<'_, u16, 2> {
807    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u16, 2>, pool: &novtb::ThreadPool) {
808        let dst_stride = into.stride();
809        let dst = into.projected();
810        let src = self.projected();
811        let bit_depth = self.bit_depth;
812        use crate::alpha_handle_u16::premultiply_alpha_gray_alpha_u16;
813        premultiply_alpha_gray_alpha_u16(
814            dst,
815            dst_stride,
816            src,
817            self.width,
818            self.height,
819            self.stride(),
820            bit_depth,
821            pool,
822        );
823    }
824
825    fn is_alpha_premultiplication_needed(&self) -> bool {
826        use crate::alpha_check::has_non_constant_cap_alpha_gray_alpha16;
827        has_non_constant_cap_alpha_gray_alpha16(self.projected(), self.width, self.stride())
828    }
829}
830
831impl AssociateAlpha<f32, 2> for ImageStore<'_, f32, 2> {
832    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, f32, 2>, pool: &novtb::ThreadPool) {
833        let dst_stride = into.stride();
834        let dst = into.projected();
835        let src = self.projected();
836        use crate::alpha_handle_f32::premultiply_alpha_gray_alpha_f32;
837        premultiply_alpha_gray_alpha_f32(
838            dst,
839            dst_stride,
840            src,
841            self.stride(),
842            self.width,
843            self.height,
844            pool,
845        );
846    }
847
848    fn is_alpha_premultiplication_needed(&self) -> bool {
849        use crate::alpha_check::has_non_constant_cap_alpha_gray_alpha_f32;
850        has_non_constant_cap_alpha_gray_alpha_f32(self.projected(), self.width, self.stride())
851    }
852}
853
854impl AssociateAlpha<u8, 4> for ImageStore<'_, u8, 4> {
855    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u8, 4>, pool: &novtb::ThreadPool) {
856        let dst_stride = into.stride();
857        let dst = into.projected();
858        let src = self.projected();
859        premultiply_alpha_rgba(
860            dst,
861            dst_stride,
862            src,
863            self.width,
864            self.height,
865            self.stride(),
866            pool,
867        );
868    }
869
870    #[cfg(not(any(
871        any(target_arch = "x86_64", target_arch = "x86"),
872        all(target_arch = "aarch64", feature = "neon")
873    )))]
874    fn is_alpha_premultiplication_needed(&self) -> bool {
875        use crate::alpha_check::has_non_constant_cap_alpha_rgba8;
876        has_non_constant_cap_alpha_rgba8(self.projected(), self.width, self.stride())
877    }
878
879    #[cfg(all(target_arch = "aarch64", feature = "neon"))]
880    fn is_alpha_premultiplication_needed(&self) -> bool {
881        use crate::neon::neon_has_non_constant_cap_alpha_rgba8;
882        neon_has_non_constant_cap_alpha_rgba8(self.projected(), self.width, self.stride())
883    }
884
885    #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
886    fn is_alpha_premultiplication_needed(&self) -> bool {
887        use crate::alpha_check::has_non_constant_cap_alpha_rgba8;
888        #[cfg(feature = "sse")]
889        use crate::sse::sse_has_non_constant_cap_alpha_rgba8;
890        #[cfg(all(target_arch = "x86_64", feature = "avx512"))]
891        if std::arch::is_x86_feature_detected!("avx512bw") {
892            use crate::avx512::avx512_has_non_constant_cap_alpha_rgba8;
893            return avx512_has_non_constant_cap_alpha_rgba8(
894                self.projected(),
895                self.width,
896                self.stride(),
897            );
898        }
899        #[cfg(all(target_arch = "x86_64", feature = "avx"))]
900        if std::arch::is_x86_feature_detected!("avx2") {
901            use crate::avx2::avx_has_non_constant_cap_alpha_rgba8;
902            return avx_has_non_constant_cap_alpha_rgba8(
903                self.projected(),
904                self.width,
905                self.stride(),
906            );
907        }
908        #[cfg(feature = "sse")]
909        if std::arch::is_x86_feature_detected!("sse4.1") {
910            return sse_has_non_constant_cap_alpha_rgba8(
911                self.projected(),
912                self.width,
913                self.stride(),
914            );
915        }
916        has_non_constant_cap_alpha_rgba8(self.projected(), self.width, self.stride())
917    }
918}
919
920impl UnassociateAlpha<u8, 4> for ImageStoreMut<'_, u8, 4> {
921    fn unpremultiply_alpha(
922        &mut self,
923        pool: &novtb::ThreadPool,
924        workload_strategy: WorkloadStrategy,
925    ) {
926        let src_stride = self.stride();
927        let width = self.width;
928        let height = self.height;
929        let dst = self.projected();
930        unpremultiply_alpha_rgba(dst, width, height, src_stride, pool, workload_strategy);
931    }
932}
933
934impl UnassociateAlpha<u8, 2> for ImageStoreMut<'_, u8, 2> {
935    fn unpremultiply_alpha(
936        &mut self,
937        pool: &novtb::ThreadPool,
938        workload_strategy: WorkloadStrategy,
939    ) {
940        let src_stride = self.stride();
941        let width = self.width;
942        let height = self.height;
943        let dst = self.projected();
944        use crate::alpha_handle_u8::unpremultiply_alpha_gray_alpha;
945        unpremultiply_alpha_gray_alpha(dst, width, height, src_stride, pool, workload_strategy);
946    }
947}
948
949impl UnassociateAlpha<f32, 2> for ImageStoreMut<'_, f32, 2> {
950    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
951        let src_stride = self.stride();
952        let width = self.width;
953        let height = self.height;
954        let dst = self.projected();
955        use crate::alpha_handle_f32::unpremultiply_alpha_gray_alpha_f32;
956        unpremultiply_alpha_gray_alpha_f32(dst, src_stride, width, height, pool);
957    }
958}
959
960impl UnassociateAlpha<u16, 2> for ImageStoreMut<'_, u16, 2> {
961    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
962        let src_stride = self.stride();
963        let width = self.width;
964        let height = self.height;
965        let bit_depth = self.bit_depth;
966        let dst = self.projected();
967        use crate::alpha_handle_u16::unpremultiply_alpha_gray_alpha_u16;
968        unpremultiply_alpha_gray_alpha_u16(dst, src_stride, width, height, bit_depth, pool);
969    }
970}
971
972impl AssociateAlpha<u16, 4> for ImageStore<'_, u16, 4> {
973    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, u16, 4>, pool: &novtb::ThreadPool) {
974        let dst_stride = into.stride();
975        let bit_depth = into.bit_depth;
976        let dst = into.projected();
977        let src = self.projected();
978        premultiply_alpha_rgba_u16(
979            dst,
980            dst_stride,
981            src,
982            self.width,
983            self.height,
984            self.stride(),
985            bit_depth,
986            pool,
987        );
988    }
989
990    #[cfg(not(any(
991        any(target_arch = "x86_64", target_arch = "x86"),
992        all(target_arch = "aarch64", feature = "neon")
993    )))]
994    fn is_alpha_premultiplication_needed(&self) -> bool {
995        use crate::alpha_check::has_non_constant_cap_alpha_rgba16;
996        has_non_constant_cap_alpha_rgba16(self.projected(), self.width, self.stride())
997    }
998
999    #[cfg(all(target_arch = "aarch64", feature = "neon"))]
1000    fn is_alpha_premultiplication_needed(&self) -> bool {
1001        use crate::neon::neon_has_non_constant_cap_alpha_rgba16;
1002        neon_has_non_constant_cap_alpha_rgba16(self.projected(), self.width, self.stride())
1003    }
1004
1005    #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
1006    fn is_alpha_premultiplication_needed(&self) -> bool {
1007        use crate::alpha_check::has_non_constant_cap_alpha_rgba16;
1008        #[cfg(feature = "sse")]
1009        use crate::sse::sse_has_non_constant_cap_alpha_rgba16;
1010        #[cfg(all(target_arch = "x86_64", feature = "avx"))]
1011        if std::arch::is_x86_feature_detected!("avx2") {
1012            use crate::avx2::avx_has_non_constant_cap_alpha_rgba16;
1013            return avx_has_non_constant_cap_alpha_rgba16(
1014                self.projected(),
1015                self.width,
1016                self.stride(),
1017            );
1018        }
1019        #[cfg(feature = "sse")]
1020        if std::arch::is_x86_feature_detected!("sse4.1") {
1021            return sse_has_non_constant_cap_alpha_rgba16(
1022                self.projected(),
1023                self.width,
1024                self.stride(),
1025            );
1026        }
1027        has_non_constant_cap_alpha_rgba16(self.projected(), self.width, self.stride())
1028    }
1029}
1030
1031impl AssociateAlpha<f32, 4> for ImageStore<'_, f32, 4> {
1032    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, f32, 4>, pool: &novtb::ThreadPool) {
1033        let src_stride = self.stride();
1034        let dst_stride = into.stride();
1035        let width = self.width;
1036        let height = self.height;
1037        let dst = into.projected();
1038        let src = self.projected();
1039        premultiply_alpha_rgba_f32(dst, dst_stride, src, src_stride, width, height, pool);
1040    }
1041
1042    fn is_alpha_premultiplication_needed(&self) -> bool {
1043        has_non_constant_cap_alpha_rgba_f32(self.projected(), self.width, self.stride())
1044    }
1045}
1046
1047#[cfg(feature = "nightly_f16")]
1048impl AssociateAlpha<f16, 4> for ImageStore<'_, f16, 4> {
1049    fn premultiply_alpha(&self, into: &mut ImageStoreMut<'_, f16, 4>, pool: &novtb::ThreadPool) {
1050        let src_stride = self.stride();
1051        let dst_stride = into.stride();
1052        let width = self.width;
1053        let height = self.height;
1054        let dst = into.projected();
1055        let src = self.projected();
1056        premultiply_alpha_rgba_f16(dst, dst_stride, src, src_stride, width, height, pool);
1057    }
1058
1059    fn is_alpha_premultiplication_needed(&self) -> bool {
1060        true
1061    }
1062}
1063
1064impl UnassociateAlpha<u16, 4> for ImageStoreMut<'_, u16, 4> {
1065    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
1066        let src_stride = self.stride();
1067        let width = self.width;
1068        let height = self.height;
1069        let bit_depth = self.bit_depth;
1070        let in_place = self.projected();
1071        unpremultiply_alpha_rgba_u16(in_place, src_stride, width, height, bit_depth, pool);
1072    }
1073}
1074
1075impl UnassociateAlpha<f32, 4> for ImageStoreMut<'_, f32, 4> {
1076    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
1077        let stride = self.stride();
1078        let width = self.width;
1079        let height = self.height;
1080        let dst = self.projected();
1081        unpremultiply_alpha_rgba_f32(dst, stride, width, height, pool);
1082    }
1083}
1084
1085#[cfg(feature = "nightly_f16")]
1086impl UnassociateAlpha<f16, 4> for ImageStoreMut<'_, f16, 4> {
1087    fn unpremultiply_alpha(&mut self, pool: &novtb::ThreadPool, _: WorkloadStrategy) {
1088        let stride = self.stride();
1089        let width = self.width;
1090        let height = self.height;
1091        let dst = self.projected();
1092        unpremultiply_alpha_rgba_f16(dst, stride, width, height, pool);
1093    }
1094}
1095
1096pub type Planar8ImageStore<'a> = ImageStore<'a, u8, 1>;
1097pub type Planar8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 1>;
1098pub type CbCr8ImageStore<'a> = ImageStore<'a, u8, 2>;
1099pub type CbCr8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 2>;
1100pub type GrayAlpha8ImageStore<'a> = ImageStore<'a, u8, 2>;
1101pub type GrayAlpha8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 2>;
1102pub type Rgba8ImageStore<'a> = ImageStore<'a, u8, 4>;
1103pub type Rgba8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 4>;
1104pub type Rgb8ImageStore<'a> = ImageStore<'a, u8, 3>;
1105pub type Rgb8ImageStoreMut<'a> = ImageStoreMut<'a, u8, 3>;
1106
1107pub type PlanarS16ImageStore<'a> = ImageStore<'a, i16, 1>;
1108pub type PlanarS16ImageStoreMut<'a> = ImageStoreMut<'a, i16, 1>;
1109pub type Planar16ImageStore<'a> = ImageStore<'a, u16, 1>;
1110pub type Planar16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 1>;
1111pub type CbCr16ImageStore<'a> = ImageStore<'a, u16, 2>;
1112pub type CbCr16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 2>;
1113pub type GrayAlpha16ImageStore<'a> = ImageStore<'a, u16, 2>;
1114pub type GrayAlpha16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 2>;
1115pub type Rgba16ImageStore<'a> = ImageStore<'a, u16, 4>;
1116pub type Rgba16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 4>;
1117pub type Rgb16ImageStore<'a> = ImageStore<'a, u16, 3>;
1118pub type Rgb16ImageStoreMut<'a> = ImageStoreMut<'a, u16, 3>;
1119
1120#[cfg(feature = "nightly_f16")]
1121pub type PlanarF16ImageStore<'a> = ImageStore<'a, f16, 1>;
1122#[cfg(feature = "nightly_f16")]
1123pub type PlanarF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 1>;
1124#[cfg(feature = "nightly_f16")]
1125pub type CbCrF16ImageStore<'a> = ImageStore<'a, f16, 2>;
1126#[cfg(feature = "nightly_f16")]
1127pub type CbCrF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 2>;
1128#[cfg(feature = "nightly_f16")]
1129pub type RgbaF16ImageStore<'a> = ImageStore<'a, f16, 4>;
1130#[cfg(feature = "nightly_f16")]
1131pub type RgbaF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 4>;
1132#[cfg(feature = "nightly_f16")]
1133pub type RgbF16ImageStore<'a> = ImageStore<'a, f16, 3>;
1134#[cfg(feature = "nightly_f16")]
1135pub type RgbF16ImageStoreMut<'a> = ImageStoreMut<'a, f16, 3>;
1136
1137pub type PlanarF32ImageStore<'a> = ImageStore<'a, f32, 1>;
1138pub type PlanarF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 1>;
1139pub type CbCrF32ImageStore<'a> = ImageStore<'a, f32, 2>;
1140pub type CbCrF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 2>;
1141pub type GrayAlphaF32ImageStore<'a> = ImageStore<'a, f32, 2>;
1142pub type GrayAlphaF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 2>;
1143pub type RgbaF32ImageStore<'a> = ImageStore<'a, f32, 4>;
1144pub type RgbaF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 4>;
1145pub type RgbF32ImageStore<'a> = ImageStore<'a, f32, 3>;
1146pub type RgbF32ImageStoreMut<'a> = ImageStoreMut<'a, f32, 3>;
1147
1148#[cfg(test)]
1149mod tests {
1150    use super::*;
1151
1152    #[test]
1153    fn image_store_alpha_test_rgba8() {
1154        let image_size = 256usize;
1155        let mut image = vec![0u8; image_size * image_size * 4];
1156        image[3 + 150 * 4] = 75;
1157        let store = ImageStore::<u8, 4>::from_slice(&image, image_size, image_size).unwrap();
1158        let has_alpha = store.is_alpha_premultiplication_needed();
1159        assert_eq!(true, has_alpha);
1160    }
1161
1162    #[test]
1163    fn check_alpha_not_exists_rgba8() {
1164        let image_size = 256usize;
1165        let image = vec![255u8; image_size * image_size * 4];
1166        let store = ImageStore::<u8, 4>::from_slice(&image, image_size, image_size).unwrap();
1167        let has_alpha = store.is_alpha_premultiplication_needed();
1168        assert_eq!(false, has_alpha);
1169    }
1170}