dither/
img.rs

1use super::RGB;
2use super::{Error, Result};
3use std::ops::{Index, IndexMut};
4use std::path::Path;
5/// Image as a flat buffer of pixels; accessible by (x, y) [Index]
6#[derive(Clone, Debug, PartialEq)]
7pub struct Img<P> {
8    buf: Vec<P>,
9    width: u32,
10}
11
12impl<P> Img<P> {
13    /// create an Img<P> from a buf and width. fails if `buf.len() % buf.width() != 0`
14    pub fn new(buf: impl IntoIterator<Item = P>, width: u32) -> Option<Self> {
15        let buf: Vec<P> = buf.into_iter().collect();
16        if width == 0 || buf.len() % width as usize != 0 {
17            None
18        } else {
19            Some(Img { buf, width })
20        }
21    }
22    /// create an Img<P> from a buf and length directly, skipping the bounds check.
23    /// ```
24    /// # use dither::prelude::*;
25    /// assert_eq!(
26    ///     unsafe{Img::from_raw_buf(vec![2, 4, 6, 8], 2)},
27    ///     Img::new(vec![2, 4, 6, 8], 2).unwrap()
28    /// );
29    /// ```
30    pub const unsafe fn from_raw_buf(buf: Vec<P>, width: u32) -> Self {
31        Img { buf, width }
32    }
33
34    /// pull the buffer out of the image as a vec.
35    /// ```
36    /// # use dither::prelude::*;
37    /// assert_eq!(Img::new(1..=4, 2).unwrap().into_vec(), vec![1, 2, 3, 4]);
38    /// ```
39    pub fn into_vec(self) -> Vec<P> {
40        self.buf
41    }
42
43    /// get the width of the image.
44    /// ```
45    /// # use dither::prelude::*;
46    /// assert_eq!(Img::new(0..12, 3).unwrap().width(), 3);
47    /// ```
48    pub fn width(&self) -> u32 {
49        self.width
50    }
51    /// returns an iterator over the pixels in the buffer
52    pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
53        self.into_iter()
54    }
55
56    /// returns an iterator that allows modifying each pixel
57    pub fn iter_mut(&mut self) -> <&mut Self as IntoIterator>::IntoIter {
58        self.buf.iter_mut()
59    }
60    /// the height of the image; i.e, `buf.len() / width`
61    /// ```
62    /// # use dither::prelude::*;
63    /// assert_eq!(Img::new(0..12, 3).unwrap().height(), 4);
64    /// ```
65    pub fn height(&self) -> u32 {
66        self.len() as u32 / self.width
67    }
68    /// map a function on P across the image buffer, converting an `Img<P>` to an `Img<Q>`
69    ///
70    /// ```
71    /// # use dither::prelude::*;
72    /// let img: Img<u8> = Img::new(1..=4, 2).unwrap();
73    /// let doubled: Img<u16> = Img::new(vec![2, 4, 6, 8], 2).unwrap();
74    /// assert_eq!(img.convert_with(|x| u16::from(x*2)), doubled);
75    /// ```
76    pub fn convert_with<Q>(self, convert: impl Fn(P) -> Q) -> Img<Q> {
77        let Img { buf, width } = self;
78        Img {
79            buf: buf.into_iter().map(convert).collect(),
80            width,
81        }
82    }
83    #[inline]
84    fn idx(&self, (x, y): (u32, u32)) -> usize {
85        ((y * self.width) + x) as usize
86    }
87    /// the length of the image, in _pixels_. equal to [Img::width()]*[Img::height()]
88    pub fn len(&self) -> usize {
89        self.buf.len()
90    }
91
92    pub fn is_empty(&self) -> bool {
93        self.len() == 0
94    }
95
96    /// Returns a reference to an element.
97    pub fn get(&self, (x, y): (u32, u32)) -> Option<&P> {
98        self.buf.get(self.idx((x, y)))
99    }
100    /// Returns a pair `(width, height)`.
101    pub fn size(&self) -> (u32, u32) {
102        (self.width, self.len() as u32 / self.width as u32)
103    }
104}
105
106impl<N: From<u8>> Img<RGB<N>> {
107    /// load an image as an RGB<N> after converting it. See [image::open] and [image::DynamicImage::to_rgb]
108    /// ```rust
109    /// use dither::prelude::*;
110    /// let img: Img<RGB<u8>> = Img::load("bunny.png").unwrap();
111    /// assert_eq!(img.size(), (480, 320));
112    /// ```
113    pub fn load(path: impl AsRef<Path>) -> Result<Self> {
114        match image::open(&path).and_then(|img| Ok(img.to_rgb())) {
115            Err(err) => Err(Error::input(err, path.as_ref())),
116            Ok(img) => Ok(Img {
117                buf: img.pixels().map(|p| RGB::from(p.0)).collect(),
118                width: img.width(),
119            }),
120        }
121    }
122}
123
124impl Img<RGB<u8>> {
125    /// save an image as a `.png` or `.jpg` to the path. the path extension determines the image type.
126    /// See [image::ImageBuffer::save]
127    pub fn save(self, path: &Path) -> Result<()> {
128        let (width, height) = self.size();
129        let buf = image::RgbImage::from_raw(width, height, self.raw_buf()).unwrap();
130        if let Err(err) = buf.save(path) {
131            Err(Error::output(err, path))
132        } else {
133            Ok(())
134        }
135    }
136    /// the raw_buf flattens out each RGB triplet;
137    /// ```
138    /// use dither::prelude::*;
139    /// let img: Img<RGB<u8>> = Img::new(vec![RGB(0, 1, 2), RGB(1, 1, 1)], 1).unwrap();
140    /// assert_eq!(img.raw_buf(), vec![0, 1, 2, 1, 1, 1]);
141    /// ```
142    pub fn raw_buf(self) -> Vec<u8> {
143        let mut raw_buf = Vec::with_capacity(self.len() * 3);
144        for RGB(r, g, b) in self.buf {
145            raw_buf.push(r);
146            raw_buf.push(g);
147            raw_buf.push(b);
148        }
149        raw_buf
150    }
151}
152
153impl<P> Index<(u32, u32)> for Img<P> {
154    type Output = P;
155    fn index(&self, (x, y): (u32, u32)) -> &P {
156        &self.buf[self.idx((x, y))]
157    }
158}
159
160impl<P> IndexMut<(u32, u32)> for Img<P> {
161    fn index_mut(&mut self, (x, y): (u32, u32)) -> &mut P {
162        let i = self.idx((x, y));
163        &mut self.buf[i]
164    }
165}
166
167impl<P> IntoIterator for Img<P> {
168    type Item = P;
169    type IntoIter = std::vec::IntoIter<P>;
170    fn into_iter(self) -> Self::IntoIter {
171        self.buf.into_iter()
172    }
173}
174
175impl<'a, P> IntoIterator for &'a Img<P> {
176    type Item = &'a P;
177    type IntoIter = std::slice::Iter<'a, P>;
178    fn into_iter(self) -> Self::IntoIter {
179        (&self.buf).iter()
180    }
181}
182
183impl<'a, P> IntoIterator for &'a mut Img<P> {
184    type Item = &'a mut P;
185    type IntoIter = std::slice::IterMut<'a, P>;
186    fn into_iter(self) -> Self::IntoIter {
187        (&mut self.buf).iter_mut()
188    }
189}