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;
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 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 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 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 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 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 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 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 #[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 #[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 pub fn size(&self) -> ImageSize {
489 ImageSize::new(self.width, self.height)
490 }
491
492 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 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 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 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 pub fn size(&self) -> ImageSize {
557 ImageSize::new(self.width, self.height)
558 }
559
560 pub fn as_bytes(&self) -> &[T] {
562 match &self.buffer {
563 BufferStore::Borrowed(p) => p,
564 BufferStore::Owned(v) => v,
565 }
566 }
567
568 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 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 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}