1use 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#[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 pub channels: usize,
59 pub width: usize,
61 pub height: usize,
63 pub stride: usize,
65 pub bit_depth: usize,
67}
68
69pub struct ImageStoreMut<'a, T, const N: usize> {
79 pub buffer: BufferStore<'a, T>,
80 pub channels: usize,
82 pub width: usize,
84 pub height: usize,
86 pub stride: usize,
88 pub bit_depth: usize,
90}
91
92pub(crate) trait CheckStoreDensity {
93 fn should_have_bit_depth(&self) -> bool;
94}
95
96pub 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 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 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 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 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 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 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 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 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 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 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 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 #[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 #[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 pub fn size(&self) -> ImageSize {
563 ImageSize::new(self.width, self.height)
564 }
565
566 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 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 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 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 pub fn size(&self) -> ImageSize {
631 ImageSize::new(self.width, self.height)
632 }
633
634 pub fn as_bytes(&self) -> &[T] {
636 match &self.buffer {
637 BufferStore::Borrowed(p) => p,
638 BufferStore::Owned(v) => v,
639 }
640 }
641
642 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 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 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}