1use crate::error::{Error, Result};
8
9#[derive(Debug, Clone)]
11pub struct Image<T> {
12 data: Vec<T>,
13 width: usize,
14 height: usize,
15}
16
17impl<T: Clone + Default> Image<T> {
18 pub fn new(width: usize, height: usize) -> Result<Self> {
20 if width == 0 || height == 0 {
21 return Err(Error::InvalidImageDimensions(width, height));
22 }
23
24 let size = width
25 .checked_mul(height)
26 .ok_or(Error::InvalidImageDimensions(width, height))?;
27
28 let mut data = Vec::new();
29 data.try_reserve_exact(size)?;
30 data.resize(size, T::default());
31
32 Ok(Self {
33 data,
34 width,
35 height,
36 })
37 }
38
39 pub fn from_vec(data: Vec<T>, width: usize, height: usize) -> Result<Self> {
41 if width == 0 || height == 0 {
42 return Err(Error::InvalidImageDimensions(width, height));
43 }
44 if data.len() != width * height {
45 return Err(Error::InvalidImageDimensions(width, height));
46 }
47 Ok(Self {
48 data,
49 width,
50 height,
51 })
52 }
53}
54
55impl<T> Image<T> {
56 #[inline]
58 pub fn width(&self) -> usize {
59 self.width
60 }
61
62 #[inline]
64 pub fn height(&self) -> usize {
65 self.height
66 }
67
68 #[inline]
70 pub fn len(&self) -> usize {
71 self.data.len()
72 }
73
74 #[inline]
76 pub fn is_empty(&self) -> bool {
77 self.data.is_empty()
78 }
79
80 #[inline]
82 pub fn get(&self, x: usize, y: usize) -> &T {
83 debug_assert!(x < self.width && y < self.height);
84 &self.data[y * self.width + x]
85 }
86
87 #[inline]
89 pub fn get_mut(&mut self, x: usize, y: usize) -> &mut T {
90 debug_assert!(x < self.width && y < self.height);
91 &mut self.data[y * self.width + x]
92 }
93
94 #[inline]
96 pub fn row(&self, y: usize) -> &[T] {
97 debug_assert!(y < self.height);
98 let start = y * self.width;
99 &self.data[start..start + self.width]
100 }
101
102 #[inline]
104 pub fn row_mut(&mut self, y: usize) -> &mut [T] {
105 debug_assert!(y < self.height);
106 let start = y * self.width;
107 &mut self.data[start..start + self.width]
108 }
109
110 #[inline]
112 pub fn data(&self) -> &[T] {
113 &self.data
114 }
115
116 #[inline]
118 pub fn data_mut(&mut self) -> &mut [T] {
119 &mut self.data
120 }
121
122 #[inline]
124 pub fn into_vec(self) -> Vec<T> {
125 self.data
126 }
127}
128
129#[derive(Debug, Clone)]
131pub struct ImageBundle<T> {
132 pub channels: Vec<Image<T>>,
134 pub width: usize,
136 pub height: usize,
138}
139
140impl<T: Clone + Default> ImageBundle<T> {
141 pub fn new(width: usize, height: usize, num_channels: usize) -> Result<Self> {
143 let mut channels = Vec::with_capacity(num_channels);
144 for _ in 0..num_channels {
145 channels.push(Image::new(width, height)?);
146 }
147 Ok(Self {
148 channels,
149 width,
150 height,
151 })
152 }
153
154 pub fn num_channels(&self) -> usize {
156 self.channels.len()
157 }
158
159 pub fn channel(&self, idx: usize) -> &Image<T> {
161 &self.channels[idx]
162 }
163
164 pub fn channel_mut(&mut self, idx: usize) -> &mut Image<T> {
166 &mut self.channels[idx]
167 }
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub enum PixelFormat {
173 Gray8,
175 GrayA8,
177 Rgb8,
179 Rgba8,
181 Gray16,
183 GrayA16,
185 Rgb16,
187 Rgba16,
189 RgbF32,
191 RgbaF32,
193}
194
195impl PixelFormat {
196 pub fn num_channels(self) -> usize {
198 match self {
199 Self::Gray8 | Self::Gray16 => 1,
200 Self::GrayA8 | Self::GrayA16 => 2,
201 Self::Rgb8 | Self::Rgb16 | Self::RgbF32 => 3,
202 Self::Rgba8 | Self::Rgba16 | Self::RgbaF32 => 4,
203 }
204 }
205
206 pub fn bytes_per_sample(self) -> usize {
208 match self {
209 Self::Gray8 | Self::GrayA8 | Self::Rgb8 | Self::Rgba8 => 1,
210 Self::Gray16 | Self::GrayA16 | Self::Rgb16 | Self::Rgba16 => 2,
211 Self::RgbF32 | Self::RgbaF32 => 4,
212 }
213 }
214
215 pub fn bytes_per_pixel(self) -> usize {
217 self.num_channels() * self.bytes_per_sample()
218 }
219
220 pub fn has_alpha(self) -> bool {
222 matches!(
223 self,
224 Self::GrayA8 | Self::GrayA16 | Self::Rgba8 | Self::Rgba16 | Self::RgbaF32
225 )
226 }
227
228 pub fn is_grayscale(self) -> bool {
230 matches!(
231 self,
232 Self::Gray8 | Self::Gray16 | Self::GrayA8 | Self::GrayA16
233 )
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240
241 #[test]
242 fn test_image_creation() {
243 let img: Image<f32> = Image::new(100, 100).unwrap();
244 assert_eq!(img.width(), 100);
245 assert_eq!(img.height(), 100);
246 assert_eq!(img.len(), 10000);
247 assert!(!img.is_empty());
248 }
249
250 #[test]
251 fn test_image_access() {
252 let mut img: Image<u8> = Image::new(10, 10).unwrap();
253 *img.get_mut(5, 5) = 42;
254 assert_eq!(*img.get(5, 5), 42);
255 }
256
257 #[test]
258 fn test_image_bundle() {
259 let bundle: ImageBundle<f32> = ImageBundle::new(100, 100, 3).unwrap();
260 assert_eq!(bundle.num_channels(), 3);
261 assert_eq!(bundle.width, 100);
262 assert_eq!(bundle.height, 100);
263 }
264
265 #[test]
266 fn test_pixel_format() {
267 assert_eq!(PixelFormat::Rgba8.num_channels(), 4);
268 assert_eq!(PixelFormat::Rgba8.bytes_per_pixel(), 4);
269 assert!(PixelFormat::Rgba8.has_alpha());
270 assert!(!PixelFormat::Rgb8.has_alpha());
271 }
272
273 #[test]
274 fn test_image_zero_width() {
275 let result: Result<Image<u8>> = Image::new(0, 10);
276 assert!(result.is_err());
277 }
278
279 #[test]
280 fn test_image_zero_height() {
281 let result: Result<Image<u8>> = Image::new(10, 0);
282 assert!(result.is_err());
283 }
284
285 #[test]
286 fn test_image_from_vec() {
287 let data = vec![1u8, 2, 3, 4, 5, 6];
288 let img = Image::from_vec(data, 3, 2).unwrap();
289 assert_eq!(img.width(), 3);
290 assert_eq!(img.height(), 2);
291 assert_eq!(*img.get(0, 0), 1);
292 assert_eq!(*img.get(2, 1), 6);
293 }
294
295 #[test]
296 fn test_image_from_vec_wrong_size() {
297 let data = vec![1u8, 2, 3, 4, 5];
298 let result = Image::from_vec(data, 3, 2);
299 assert!(result.is_err());
300 }
301
302 #[test]
303 fn test_image_from_vec_zero_dims() {
304 let data = vec![1u8, 2, 3];
305 assert!(Image::from_vec(data.clone(), 0, 3).is_err());
306 assert!(Image::from_vec(data, 3, 0).is_err());
307 }
308
309 #[test]
310 fn test_image_row_access() {
311 let data = vec![1u8, 2, 3, 4, 5, 6];
312 let img = Image::from_vec(data, 3, 2).unwrap();
313 assert_eq!(img.row(0), &[1, 2, 3]);
314 assert_eq!(img.row(1), &[4, 5, 6]);
315 }
316
317 #[test]
318 fn test_image_row_mut() {
319 let data = vec![1u8, 2, 3, 4, 5, 6];
320 let mut img = Image::from_vec(data, 3, 2).unwrap();
321 img.row_mut(0)[1] = 99;
322 assert_eq!(*img.get(1, 0), 99);
323 }
324
325 #[test]
326 fn test_image_data_access() {
327 let data = vec![1u8, 2, 3, 4];
328 let mut img = Image::from_vec(data, 2, 2).unwrap();
329 assert_eq!(img.data(), &[1, 2, 3, 4]);
330 img.data_mut()[0] = 100;
331 assert_eq!(img.data()[0], 100);
332 }
333
334 #[test]
335 fn test_image_into_vec() {
336 let data = vec![1u8, 2, 3, 4];
337 let img = Image::from_vec(data.clone(), 2, 2).unwrap();
338 let recovered = img.into_vec();
339 assert_eq!(recovered, data);
340 }
341
342 #[test]
343 fn test_image_bundle_channel_access() {
344 let mut bundle: ImageBundle<u8> = ImageBundle::new(10, 10, 3).unwrap();
345 *bundle.channel_mut(1).get_mut(5, 5) = 42;
346 assert_eq!(*bundle.channel(1).get(5, 5), 42);
347 }
348
349 #[test]
350 fn test_pixel_format_all_variants() {
351 let formats = [
353 (PixelFormat::Gray8, 1, 1, false, true),
354 (PixelFormat::GrayA8, 2, 1, true, true),
355 (PixelFormat::Rgb8, 3, 1, false, false),
356 (PixelFormat::Rgba8, 4, 1, true, false),
357 (PixelFormat::Gray16, 1, 2, false, true),
358 (PixelFormat::GrayA16, 2, 2, true, true),
359 (PixelFormat::Rgb16, 3, 2, false, false),
360 (PixelFormat::Rgba16, 4, 2, true, false),
361 (PixelFormat::RgbF32, 3, 4, false, false),
362 (PixelFormat::RgbaF32, 4, 4, true, false),
363 ];
364
365 for (format, channels, bytes_per_sample, has_alpha, is_gray) in formats {
366 assert_eq!(format.num_channels(), channels, "{:?}", format);
367 assert_eq!(format.bytes_per_sample(), bytes_per_sample, "{:?}", format);
368 assert_eq!(
369 format.bytes_per_pixel(),
370 channels * bytes_per_sample,
371 "{:?}",
372 format
373 );
374 assert_eq!(format.has_alpha(), has_alpha, "{:?}", format);
375 assert_eq!(format.is_grayscale(), is_gray, "{:?}", format);
376 }
377 }
378}