1mod rgb;
2pub use rgb::RGB;
3
4pub use image;
6use std::ops::{Index, IndexMut};
7use std::path::Path;
8
9pub type Result<T> = std::result::Result<T, image::ImageError>;
11pub type Error = image::ImageError;
13
14
15pub fn clamp_f64_to_u8(n: f64) -> u8 {
22 match n {
23 n if n > 255.0 => 255,
24 n if n < 0.0 => 0,
25 n => n.round() as u8,
26 }
27}
28
29#[derive(Clone, Debug, PartialEq)]
31pub struct Img<P> {
32 buf: Vec<P>,
33 width: u32,
34}
35
36impl<P> Img<P> {
37 pub fn new(buf: impl IntoIterator<Item = P>, width: u32) -> Option<Self> {
39 let buf: Vec<P> = buf.into_iter().collect();
40 if width == 0 || buf.len() % width as usize != 0 {
41 None
42 } else {
43 Some(Img { buf, width })
44 }
45 }
46 pub const unsafe fn from_raw_buf(buf: Vec<P>, width: u32) -> Self {
55 Img { buf, width }
56 }
57
58 pub fn into_vec(self) -> Vec<P> {
64 self.buf
65 }
66
67 pub fn width(&self) -> u32 {
73 self.width
74 }
75 pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
77 self.into_iter()
78 }
79
80 pub fn iter_mut(&mut self) -> <&mut Self as IntoIterator>::IntoIter {
82 self.buf.iter_mut()
83 }
84 pub fn height(&self) -> u32 {
90 self.len() as u32 / self.width
91 }
92 pub fn convert_with<Q>(self, convert: impl Fn(P) -> Q) -> Img<Q> {
101 let Img { buf, width } = self;
102 Img {
103 buf: buf.into_iter().map(convert).collect(),
104 width,
105 }
106 }
107 #[inline]
108 fn idx(&self, (x, y): (u32, u32)) -> usize {
109 ((y * self.width) + x) as usize
110 }
111 pub fn len(&self) -> usize {
113 self.buf.len()
114 }
115
116 pub fn is_empty(&self) -> bool {
117 self.len() == 0
118 }
119
120 pub fn get(&self, (x, y): (u32, u32)) -> Option<&P> {
122 self.buf.get(self.idx((x, y)))
123 }
124 pub fn size(&self) -> (u32, u32) {
126 (self.width, self.len() as u32 / self.width as u32)
127 }
128}
129
130impl<N: From<u8>> Img<RGB<N>> {
131 pub fn load(path: impl AsRef<Path>) -> Result<Self> {
138 let img = image::open(&path)?.to_rgb();
139 Ok(Img {
140 buf: img.pixels().map(|p| RGB::from(p.data)).collect(),
141 width: img.width(),
142 })
143 }
144}
145
146impl Img<RGB<u8>> {
147 pub fn save(self, path: &Path) -> Result<()> {
150 let (width, height) = self.size();
151 let buf = image::RgbImage::from_raw(width, height, self.raw_buf()).unwrap();
152 Ok(buf.save(path)?)
153 }
154 pub fn raw_buf(self) -> Vec<u8> {
161 let mut raw_buf = Vec::with_capacity(self.len() * 3);
162 for RGB(r, g, b) in self.buf {
163 raw_buf.push(r);
164 raw_buf.push(g);
165 raw_buf.push(b);
166 }
167 raw_buf
168 }
169}
170
171impl<P> Index<(u32, u32)> for Img<P> {
172 type Output = P;
173 fn index(&self, (x, y): (u32, u32)) -> &P {
174 &self.buf[self.idx((x, y))]
175 }
176}
177
178impl<P> IndexMut<(u32, u32)> for Img<P> {
179 fn index_mut(&mut self, (x, y): (u32, u32)) -> &mut P {
180 let i = self.idx((x, y));
181 &mut self.buf[i]
182 }
183}
184
185impl<P> IntoIterator for Img<P> {
186 type Item = P;
187 type IntoIter = std::vec::IntoIter<P>;
188 fn into_iter(self) -> Self::IntoIter {
189 self.buf.into_iter()
190 }
191}
192
193impl<'a, P> IntoIterator for &'a Img<P> {
194 type Item = &'a P;
195 type IntoIter = std::slice::Iter<'a, P>;
196 fn into_iter(self) -> Self::IntoIter {
197 (&self.buf).iter()
198 }
199}
200
201impl<'a, P> IntoIterator for &'a mut Img<P> {
202 type Item = &'a mut P;
203 type IntoIter = std::slice::IterMut<'a, P>;
204 fn into_iter(self) -> Self::IntoIter {
205 (&mut self.buf).iter_mut()
206 }
207}
208
209#[test]
210fn test_save_and_load() {
211 let img = load_test_image();
212 let mut output = std::env::current_dir().unwrap();
213
214 output.push("save_load_test.png");
215 img.clone().save(&output).unwrap();
216
217 assert_eq!(img, Img::load(&output).unwrap());
218 std::fs::remove_file(output).unwrap();
219}
220
221fn load_test_image() -> Img<RGB<u8>> {
222 let mut input = std::env::current_dir().unwrap();
223 input.push("bunny.png");
224
225 Img::load(&input).unwrap()
226}