cvr/
rgba.rs

1//! `rgba` contains various data structures for working in the RGBA color space.
2//!
3
4extern crate minivec;
5
6/// `Image` represents any `RGBA` image. Internally, it stores each channel as an independent
7/// allocation which enables such things as constant-time channel swapping along with making the
8/// data cheaper to copy to a GPU which expects `CHW` ordering vs the packed format `HWC`.
9///
10#[derive(Default)]
11pub struct Image<T>
12where
13  T: crate::Numeric,
14{
15  pub(super) r: minivec::MiniVec<T>,
16  pub(super) g: minivec::MiniVec<T>,
17  pub(super) b: minivec::MiniVec<T>,
18  pub(super) a: minivec::MiniVec<T>,
19  pub(super) h: usize,
20  pub(super) w: usize,
21}
22
23impl<T> Image<T>
24where
25  T: crate::Numeric,
26{
27  /// `r` returns an immutable reference to the image's red channel as a `&[T]`.
28  ///
29  #[must_use]
30  pub fn r(&self) -> &[T] {
31    self.r.as_slice()
32  }
33
34  /// `g` returns an immutable reference to the image's green channel as a `&[T]`.
35  ///
36  #[must_use]
37  pub fn g(&self) -> &[T] {
38    self.g.as_slice()
39  }
40
41  /// `b` returns an immutable reference to the image's blue channel as a `&[T]`.
42  ///
43  #[must_use]
44  pub fn b(&self) -> &[T] {
45    self.b.as_slice()
46  }
47
48  /// `a` returns an immutable reference to the image's alpha channel as a `&[T]`.
49  ///
50  #[must_use]
51  pub fn a(&self) -> &[T] {
52    self.a.as_slice()
53  }
54
55  /// `width` returns the number of columns in the image.
56  ///
57  #[must_use]
58  pub fn width(&self) -> usize {
59    self.w
60  }
61
62  /// `height` returns the number of rows in the image.
63  ///
64  #[must_use]
65  pub fn height(&self) -> usize {
66    self.h
67  }
68
69  /// `rgba_iter` returns a `cvr::rgba::Iter` to the underlying image data.
70  ///
71  #[must_use]
72  pub fn rgba_iter(&self) -> Iter<'_, T> {
73    Iter::new(&self.r, &self.g, &self.b, &self.a)
74  }
75
76  /// `rgb_iter` returns a `cvr::rgb::Iter` to the underlying image data.
77  ///
78  #[must_use]
79  pub fn rgb_iter(&self) -> crate::rgb::Iter<'_, T> {
80    crate::rgb::Iter::new(&self.r, &self.g, &self.b)
81  }
82}
83
84/// `Iter` enables the simultaneous traversal of 4 separate channels of image data. It works
85/// with any type that can be converted to a `&[Numeric]`. Image data is returned pixel-by-pixel
86/// in a `[N; 4]` format with `(R, G, B, A)` ordering.
87///
88pub struct Iter<'a, N>
89where
90  N: crate::Numeric,
91{
92  r: std::slice::Iter<'a, N>,
93  g: std::slice::Iter<'a, N>,
94  b: std::slice::Iter<'a, N>,
95  a: std::slice::Iter<'a, N>,
96}
97
98/// `new` constructs a new `Iter` using the backing `&[N]` of the types passed in by the user.
99///
100/// # Example
101/// ```
102/// let r = vec![1, 2, 3];
103/// let g = vec![4, 5, 6];
104/// let b = vec![7, 8, 9];
105/// let a = vec![255, 255, 255];
106///
107/// let rgb_iter = cvr::rgba::Iter::new(&r, &g, &b, &a);
108/// ```
109///
110impl<'a, N> Iter<'a, N>
111where
112  N: crate::Numeric,
113{
114  /// `new` returns an [`Iter`] that traverses the provided slices.
115  ///
116  pub fn new<R>(r: &'a R, g: &'a R, b: &'a R, a: &'a R) -> Self
117  where
118    R: std::convert::AsRef<[N]>,
119  {
120    Self {
121      r: r.as_ref().iter(),
122      g: g.as_ref().iter(),
123      b: b.as_ref().iter(),
124      a: a.as_ref().iter(),
125    }
126  }
127}
128
129impl<'a, N> std::iter::Iterator for Iter<'a, N>
130where
131  N: crate::Numeric,
132{
133  type Item = [N; 4];
134
135  fn next(&mut self) -> Option<Self::Item> {
136    match (self.r.next(), self.g.next(), self.b.next(), self.a.next()) {
137      (Some(r), Some(g), Some(b), Some(a)) => Some([*r, *g, *b, *a]),
138      _ => None,
139    }
140  }
141}