1use ndarray::{ArrayD, CowArray, IxDyn};
2use num_complex::Complex;
3use std::{
4 marker::PhantomData,
5 ops::{Deref, DerefMut}
6};
7use super::{PixelStorage, SampleFormat};
8use crate::error::DowncastDynImageError as DowncastError;
9
10#[derive(Clone, Debug)]
17pub enum DynImageData {
18 UInt8(ImageData<u8>),
20 UInt16(ImageData<u16>),
22 UInt32(ImageData<u32>),
24 UInt64(ImageData<u64>),
26 Float32(ImageData<f32>),
28 Float64(ImageData<f64>),
30 Complex32(ImageData<Complex<f32>>),
32 Complex64(ImageData<Complex<f64>>),
34}
35impl DynImageData {
36 pub fn sample_format(&self) -> SampleFormat {
38 match self {
39 DynImageData::UInt8(_) => SampleFormat::UInt8,
40 DynImageData::UInt16(_) => SampleFormat::UInt16,
41 DynImageData::UInt32(_) => SampleFormat::UInt32,
42 DynImageData::UInt64(_) => SampleFormat::UInt64,
43 DynImageData::Float32(_) => SampleFormat::Float32,
44 DynImageData::Float64(_) => SampleFormat::Float64,
45 DynImageData::Complex32(_) => SampleFormat::Complex32,
46 DynImageData::Complex64(_) => SampleFormat::Complex64,
47 }
48 }
49}
50macro_rules! try_into_impl {
51 ($enum:ident, $t:ty) => {
52 #[doc=concat!("Returns `Ok(ImageData<", stringify!($t), ">)` for [`", stringify!($enum), "`](Self::", stringify!($enum), ") variants, and `Err(())` otherwise")]
53 impl TryInto<ImageData<$t>> for DynImageData {
54 type Error = DowncastError;
55 fn try_into(self) -> Result<ImageData<$t>, Self::Error> {
56 match self {
57 Self::$enum(raw) => Ok(raw),
58 _ => Err(DowncastError(stringify!(ident))),
59 }
60 }
61 }
62 }
63}
64
65try_into_impl!(UInt8, u8);
66try_into_impl!(UInt16, u16);
67try_into_impl!(UInt32, u32);
68try_into_impl!(UInt64, u64);
69try_into_impl!(Float32, f32);
70try_into_impl!(Float64, f64);
71try_into_impl!(Complex32, Complex<f32>);
72try_into_impl!(Complex64, Complex<f64>);
73
74pub(crate) trait IntoDynImageData {
77 fn into_dyn_img(self, layout: PixelStorage) -> DynImageData;
78}
79macro_rules! into_impl {
80 ($enum:ident, $t:ty) => {
81 impl IntoDynImageData for ArrayD<$t> {
82 fn into_dyn_img(self, layout: PixelStorage) -> DynImageData {
89 assert!(self.shape().len() >= 2);
90 DynImageData::$enum(ImageData::<$t>::new(self, layout))
91 }
92 }
93 }
94}
95into_impl!(UInt8, u8);
96into_impl!(UInt16, u16);
97into_impl!(UInt32, u32);
98into_impl!(UInt64, u64);
99into_impl!(Float32, f32);
100into_impl!(Float64, f64);
101into_impl!(Complex32, Complex<f32>);
102into_impl!(Complex64, Complex<f64>);
103
104use memory_layout::*;
105
106#[derive(Debug)]
141pub struct ImageData<T, L: Layout = Raw> {
142 inner: ArrayD<T>,
143 layout: L::Storage,
149}
150impl<T, L: Layout> Clone for ImageData<T, L> where T: Clone {
151 fn clone(&self) -> Self {
152 Self { inner: self.inner.clone(), layout: self.layout.clone() }
153 }
154}
155impl<T, L: Layout> ImageData<T, L> where T: Clone {
156 pub fn into_planar_layout(self) -> ImageData<T, Planar> {
161 L::into_planar(self)
162 }
163 pub fn into_normal_layout(self) -> ImageData<T, Normal> {
167 L::into_normal(self)
168 }
169 pub fn to_planar_layout(&self) -> CowImageData<'_, T, Planar> {
185 L::to_planar(self)
186 }
187 pub fn to_normal_layout(&self) -> CowImageData<'_, T, Normal> {
203 L::to_normal(self)
204 }
205 pub fn layout(&self) -> PixelStorage {
207 L::layout(&self)
208 }
209 pub fn num_channels(&self) -> usize {
211 match self.layout() {
212 PixelStorage::Planar => *self.inner.shape().first().unwrap(),
213 PixelStorage::Normal => *self.inner.shape().last().unwrap(),
214 }
215 }
216 pub fn num_dimensions(&self) -> usize {
218 self.inner.shape().len() - 1
219 }
220}
221impl<T> ImageData<T, Raw> {
222 fn new(buf: ArrayD<T>, layout: PixelStorage) -> Self {
223 Self {
224 inner: buf,
225 layout,
226 }
227 }
228 pub fn accept_current_layout(self) -> ImageData<T, Accept> {
230 ImageData::<T, Accept> {
231 inner: self.inner,
232 layout: self.layout,
233 }
234 }
235}
236impl<T, L: Known> Deref for ImageData<T, L> {
237 type Target = ArrayD<T>;
238
239 fn deref(&self) -> &Self::Target {
240 &self.inner
241 }
242}
243impl<T, L: Known> DerefMut for ImageData<T, L> {
244 fn deref_mut(&mut self) -> &mut Self::Target {
245 &mut self.inner
246 }
247}
248
249#[derive(Clone, Debug)]
251pub struct CowImageData<'a, T, L: Layout> {
252 inner: CowArray<'a, T, IxDyn>,
253 layout: L::Storage,
254}
255impl<'a, T, L: Layout> CowImageData<'a, T, L> where T: Clone {
256 pub fn to_owned(&self) -> ImageData<T, L> {
258 ImageData::<T, L> {
259 inner: self.inner.to_owned(),
260 layout: self.layout.clone(),
261 }
262 }
263}
264impl<'a, T, L: Layout> From<&'a ImageData<T, L>> for CowImageData<'a, T, L> {
265 fn from(value: &'a ImageData<T, L>) -> Self {
266 Self {
267 inner: (&value.inner).into(),
268 layout: value.layout.clone(),
269 }
270 }
271}
272impl<'a, T, L: Layout> From<ImageData<T, L>> for CowImageData<'a, T, L> {
273 fn from(value: ImageData<T, L>) -> Self {
274 Self {
275 inner: value.inner.into(),
276 layout: value.layout.clone(),
277 }
278 }
279}
280impl<'a, T, L: Known> Deref for CowImageData<'a, T, L> {
281 type Target = CowArray<'a, T, IxDyn>;
282
283 fn deref(&self) -> &Self::Target {
284 &self.inner
285 }
286}
287impl<'a, T, L: Known> DerefMut for CowImageData<'a, T, L> {
288 fn deref_mut(&mut self) -> &mut Self::Target {
289 &mut self.inner
290 }
291}
292
293pub mod memory_layout {
295 use super::*;
296 use std::fmt::Debug;
297 pub(crate) use sealed::Layout;
298
299 mod sealed {
300 use super::*;
301 pub trait Layout: Sized {
302 type Storage: Clone + Debug;
303 fn into_planar<T: Clone>(img: ImageData<T, Self>) -> ImageData<T, Planar>;
304 fn into_normal<T: Clone>(img: ImageData<T, Self>) -> ImageData<T, Normal>;
305 fn to_planar<T: Clone>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Planar>;
306 fn to_normal<T: Clone>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Normal>;
307 fn layout<T>(img: &ImageData<T, Self>) -> PixelStorage;
308 }
309 }
310
311 fn normal_to_planar<T>(buf: ArrayD<T>) -> ArrayD<T> where T: Clone {
316 let num_axes = buf.shape().len();
317 let mut indices: Vec<_> = (0..num_axes).into_iter().collect();
318 indices.rotate_right(1);
319
320 buf.permuted_axes(indices.as_slice())
321 .as_standard_layout()
322 .to_owned()
323 }
324 fn planar_to_normal<T>(buf: ArrayD<T>) -> ArrayD<T> where T: Clone {
325 let num_axes = buf.shape().len();
326 let mut indices: Vec<_> = (0..num_axes).into_iter().collect();
327 indices.rotate_left(1);
328
329 buf.permuted_axes(indices.as_slice())
330 .as_standard_layout()
331 .to_owned()
332 }
333
334 #[derive(Clone, Debug)]
348 pub struct Planar;
349 impl Layout for Planar {
350 type Storage = PhantomData<Self>;
351
352 #[inline]
353 fn into_planar<T>(img: ImageData<T, Self>) -> ImageData<T, Planar> {
354 img
355 }
356
357 fn into_normal<T: Clone>(img: ImageData<T, Self>) -> ImageData<T, Normal> {
358 ImageData::<T, Normal> {
359 inner: planar_to_normal(img.inner),
360 layout: PhantomData,
361 }
362 }
363
364 #[inline]
365 fn to_planar<T>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Planar> {
366 img.into()
367 }
368
369 #[inline]
370 fn to_normal<T: Clone>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Normal> {
371 Self::into_normal(img.clone()).into()
372 }
373
374 #[inline]
375 fn layout<T>(_img: &ImageData<T, Self>) -> PixelStorage {
376 PixelStorage::Planar
377 }
378 }
379
380 #[derive(Clone, Debug)]
394 pub struct Normal;
395 impl Layout for Normal {
396 type Storage = PhantomData<Self>;
397
398 fn into_planar<T: Clone>(img: ImageData<T, Self>) -> ImageData<T, Planar> {
399 ImageData::<T, Planar> {
400 inner: normal_to_planar(img.inner),
401 layout: PhantomData,
402 }
403 }
404
405 #[inline]
406 fn into_normal<T>(img: ImageData<T, Self>) -> ImageData<T, Normal> {
407 img
408 }
409
410 #[inline]
411 fn to_planar<T: Clone>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Planar> {
412 Self::into_planar(img.clone()).into()
413 }
414
415 #[inline]
416 fn to_normal<T>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Normal> {
417 img.into()
418 }
419
420 #[inline]
421 fn layout<T>(_img: &ImageData<T, Self>) -> PixelStorage {
422 PixelStorage::Normal
423 }
424 }
425
426 #[derive(Clone, Debug)]
432 pub struct Raw;
433 impl Layout for Raw {
434 type Storage = PixelStorage;
435 fn into_planar<T: Clone>(img: ImageData<T, Self>) -> ImageData<T, Planar> {
436 ImageData::<T, Planar> {
437 inner: match img.layout {
438 PixelStorage::Planar => img.inner,
439 PixelStorage::Normal => normal_to_planar(img.inner),
440 },
441 layout: PhantomData,
442 }
443 }
444
445 fn into_normal<T: Clone>(img: ImageData<T, Self>) -> ImageData<T, Normal> {
446 ImageData::<T, Normal> {
447 inner: match img.layout {
448 PixelStorage::Planar => planar_to_normal(img.inner),
449 PixelStorage::Normal => img.inner,
450 },
451 layout: PhantomData,
452 }
453 }
454
455 fn to_planar<T: Clone>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Planar> {
456 CowImageData::<T, Planar> {
457 inner: match img.layout {
458 PixelStorage::Planar => (&img.inner).into(),
459 PixelStorage::Normal => normal_to_planar(img.inner.clone()).into(),
460 },
461 layout: PhantomData,
462 }
463 }
464
465 fn to_normal<T: Clone>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Normal> {
466 CowImageData::<T, Normal> {
467 inner: match img.layout {
468 PixelStorage::Planar => planar_to_normal(img.inner.clone()).into(),
469 PixelStorage::Normal => (&img.inner).into(),
470 },
471 layout: PhantomData,
472 }
473 }
474
475 #[inline]
476 fn layout<T>(img: &ImageData<T, Self>) -> PixelStorage {
477 img.layout
478 }
479 }
480
481 #[derive(Clone, Debug)]
483 pub struct Accept;
484 impl Layout for Accept {
485 type Storage = <Raw as Layout>::Storage;
486
487 fn into_planar<T: Clone>(img: ImageData<T, Self>) -> ImageData<T, Planar> {
488 ImageData::<T, Planar> {
489 inner: match img.layout {
490 PixelStorage::Planar => img.inner,
491 PixelStorage::Normal => normal_to_planar(img.inner),
492 },
493 layout: PhantomData,
494 }
495 }
496
497 fn into_normal<T: Clone>(img: ImageData<T, Self>) -> ImageData<T, Normal> {
498 ImageData::<T, Normal> {
499 inner: match img.layout {
500 PixelStorage::Planar => planar_to_normal(img.inner),
501 PixelStorage::Normal => img.inner,
502 },
503 layout: PhantomData,
504 }
505 }
506
507 fn to_planar<T: Clone>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Planar> {
508 CowImageData::<T, Planar> {
509 inner: match img.layout {
510 PixelStorage::Planar => (&img.inner).into(),
511 PixelStorage::Normal => normal_to_planar(img.inner.clone()).into(),
512 },
513 layout: PhantomData,
514 }
515 }
516
517 fn to_normal<T: Clone>(img: &ImageData<T, Self>) -> CowImageData<'_, T, Normal> {
518 CowImageData::<T, Normal> {
519 inner: match img.layout {
520 PixelStorage::Planar => planar_to_normal(img.inner.clone()).into(),
521 PixelStorage::Normal => (&img.inner).into(),
522 },
523 layout: PhantomData,
524 }
525 }
526
527 fn layout<T>(img: &ImageData<T, Self>) -> PixelStorage {
528 img.layout
529 }
530 }
531
532 pub(crate) trait Known: Layout {}
533 impl Known for Planar {}
534 impl Known for Normal {}
535 impl Known for Accept {}
536}
537
538#[cfg(test)]
539mod tests {
540 use super::*;
541 use std::ptr;
542 use ndarray::{s, Array3, ArrayD};
543
544 #[test]
545 fn cow_no_premature_copy() {
546 let arr = ArrayD::zeros(IxDyn(&[1]));
548
549 let mut cow = CowImageData::<u16, Accept> {
550 inner: (&arr).into(),
551 layout: PixelStorage::Planar,
552 };
553 let inner = cow.inner.as_slice().unwrap().as_ptr();
554 let inner_clone = cow.inner.clone().as_slice().unwrap().as_ptr();
555 let clone = cow.clone().as_slice().unwrap().as_ptr();
556 let to_owned = cow.to_owned().as_slice().unwrap().as_ptr();
557 let deref = cow.deref().as_slice().unwrap().as_ptr();
558 let mut_deref = cow.deref_mut().as_slice().unwrap().as_ptr();
559 let mut_slice = cow.deref_mut().as_slice_mut().unwrap().as_ptr();
560 assert!(ptr::eq(inner, inner_clone));
561 assert!(ptr::eq(inner_clone, clone));
563 assert!(!ptr::eq(clone, to_owned));
564 assert!(ptr::eq(clone, deref));
565 assert!(ptr::eq(deref, mut_deref));
567 assert!(!ptr::eq(mut_deref, mut_slice));
568
569 let planar = ImageData::<u16, Planar> {
572 inner: arr.clone(),
573 layout: PhantomData,
574 };
575 let mut cow = planar.to_planar_layout();
576 assert!(ptr::eq(planar.as_slice().unwrap(), cow.as_slice().unwrap()));
577 assert!(!ptr::eq(planar.as_slice().unwrap(), cow.as_slice_mut().unwrap()));
579
580 let raw_planar = ImageData::<u16, Raw> {
581 inner: arr.clone(),
582 layout: PixelStorage::Planar,
583 };
584 let mut cow = raw_planar.to_planar_layout();
585 assert!(ptr::eq(raw_planar.inner.as_slice().unwrap(), cow.as_slice().unwrap()));
586 assert!(!ptr::eq(raw_planar.inner.as_slice().unwrap(), cow.as_slice_mut().unwrap()));
588
589 let accept_planar = raw_planar.accept_current_layout();
590 let mut cow = accept_planar.to_planar_layout();
591 assert!(ptr::eq(accept_planar.as_slice().unwrap(), cow.as_slice().unwrap()));
592 assert!(!ptr::eq(accept_planar.as_slice().unwrap(), cow.as_slice_mut().unwrap()));
594
595 let normal = ImageData::<u16, Normal> {
598 inner: arr.clone(),
599 layout: PhantomData,
600 };
601 let cow = normal.to_planar_layout();
602 assert!(!ptr::eq(normal.as_slice().unwrap(), cow.as_slice().unwrap()));
603
604 let raw_normal = ImageData::<u16, Raw> {
605 inner: arr.clone(),
606 layout: PixelStorage::Normal,
607 };
608 let cow = raw_normal.to_planar_layout();
609 assert!(!ptr::eq(raw_normal.inner.as_slice().unwrap(), cow.as_slice().unwrap()));
610
611 let accept_normal = raw_normal.accept_current_layout();
612 let cow = accept_normal.to_planar_layout();
613 assert!(!ptr::eq(accept_normal.as_slice().unwrap(), cow.as_slice().unwrap()));
614
615 let normal = ImageData::<u16, Normal> {
618 inner: arr.clone(),
619 layout: PhantomData,
620 };
621 let mut cow = normal.to_normal_layout();
622 assert!(ptr::eq(normal.as_slice().unwrap(), cow.as_slice().unwrap()));
623 assert!(!ptr::eq(normal.as_slice().unwrap(), cow.as_slice_mut().unwrap()));
625
626 let raw_normal = ImageData::<u16, Raw> {
627 inner: arr.clone(),
628 layout: PixelStorage::Normal,
629 };
630 let mut cow = raw_normal.to_normal_layout();
631 assert!(ptr::eq(raw_normal.inner.as_slice().unwrap(), cow.as_slice().unwrap()));
632 assert!(!ptr::eq(raw_normal.inner.as_slice().unwrap(), cow.as_slice_mut().unwrap()));
634
635 let accept_normal = raw_normal.accept_current_layout();
636 let mut cow = accept_normal.to_normal_layout();
637 assert!(ptr::eq(accept_normal.as_slice().unwrap(), cow.as_slice().unwrap()));
638 assert!(!ptr::eq(accept_normal.as_slice().unwrap(), cow.as_slice_mut().unwrap()));
640
641 let arr = ArrayD::zeros(IxDyn(&[256, 256]));
644 let planar = ImageData::<u16, Planar> {
645 inner: arr.clone(),
646 layout: PhantomData,
647 };
648 let cow = planar.to_normal_layout();
649 assert!(!ptr::eq(planar.as_slice().unwrap(), cow.as_slice().unwrap()));
650
651 let raw_planar = ImageData::<u16, Raw> {
652 inner: arr.clone(),
653 layout: PixelStorage::Planar,
654 };
655 let cow = raw_planar.to_normal_layout();
656 assert!(!ptr::eq(raw_planar.inner.as_slice().unwrap(), cow.as_slice().unwrap()));
657
658 let accept_planar = raw_planar.accept_current_layout();
659 let cow = accept_planar.to_normal_layout();
660 assert!(!ptr::eq(accept_planar.as_slice().unwrap(), cow.as_slice().unwrap()));
661 }
662
663 #[test]
664 fn layout_conversions() {
665 let mut array: Array3<u8> = Array3::zeros((200, 250, 3)); for ((x, y, z), v) in array.indexed_iter_mut() {
668 *v = match z {
669 0 => y as u8,
670 1 => x as u8,
671 2 => 255 - (x as u8).min(y as u8),
672 _ => unreachable!(),
673 };
674 }
675
676 macro_rules! test_with_origin {
677 ($l:ty, $layout:expr, $sanity:expr) => {
678 let raw = ImageData::<u8, $l> {
679 inner: array.clone().into_dyn(),
680 layout: $layout,
681 };
682 assert_eq!(raw.layout(), $sanity);
683
684 let into_planar = raw.clone().into_planar_layout();
685 let into_normal = raw.clone().into_normal_layout();
686 let to_planar = raw.to_planar_layout();
687 let to_normal = raw.to_normal_layout();
688 assert_eq!(into_planar.shape(), &[3, 200, 250]);
689 assert_eq!(into_normal.shape(), &[200, 250, 3]);
690 assert_eq!(to_planar.shape(), &[3, 200, 250]);
691 assert_eq!(to_normal.shape(), &[200, 250, 3]);
692 assert_eq!(into_planar.layout(), PixelStorage::Planar);
693 assert_eq!(into_normal.layout(), PixelStorage::Normal);
694 assert_eq!(into_planar.num_channels(), 3);
695 assert_eq!(into_normal.num_channels(), 3);
696 assert_eq!(into_planar.num_dimensions(), 2);
697 assert_eq!(into_normal.num_dimensions(), 2);
698 for c in 0..3 {
702 assert!(to_planar.slice(s![c, .., ..]) == to_normal.slice(s![.., .., c]));
704 assert_eq!(to_normal.slice(s![.., .., c]), into_planar.slice(s![c, .., ..]));
705 assert_eq!(into_planar.slice(s![c, .., ..]), into_normal.slice(s![.., .., c]));
706 }
707 }
708 }
709
710 test_with_origin!(Normal, PhantomData, PixelStorage::Normal);
711 test_with_origin!(Raw, PixelStorage::Normal, PixelStorage::Normal);
712 test_with_origin!(Accept, PixelStorage::Normal, PixelStorage::Normal);
713
714 array = array.into_shape((3, 200, 250)).unwrap();
715
716 test_with_origin!(Planar, PhantomData, PixelStorage::Planar);
717 test_with_origin!(Raw, PixelStorage::Planar, PixelStorage::Planar);
718 test_with_origin!(Accept, PixelStorage::Planar, PixelStorage::Planar);
719 }
720
721 #[test]
722 fn dyn_image_conversions() {
723 macro_rules! test_conversion {
724 ($i:ident, $t:ty) => {
725 let arr = ArrayD::<$t>::zeros(IxDyn(&[2, 3, 4, 5]));
726 let there = arr.into_dyn_img(PixelStorage::Normal);
727 assert!(matches!(there, DynImageData::$i(_)));
728 let back_again: Result<ImageData<$t>, _> = there.try_into();
729 assert!(back_again.is_ok());
730 }
731 }
732 test_conversion!(UInt8, u8);
733 test_conversion!(UInt16, u16);
734 test_conversion!(UInt32, u32);
735 test_conversion!(UInt64, u64);
736 test_conversion!(Float32, f32);
737 test_conversion!(Float64, f64);
738 test_conversion!(Complex32, Complex<f32>);
739 test_conversion!(Complex64, Complex<f64>);
740 }
741}