1use crate::{BoundsCheckError, ColorInfo, ImageMut, ImageRef, ImageRefExt, PixelFormat, infer};
2
3#[derive(Debug, Clone)]
5pub struct Image<S> {
6 format: PixelFormat,
7 buffer: BufferKind<S>,
8 strides: Vec<usize>,
9 width: usize,
10 height: usize,
11
12 color: ColorInfo,
13}
14
15#[derive(Debug, Clone)]
16pub enum BufferKind<S> {
17 Whole(S),
18 Split(Vec<S>),
19}
20
21#[derive(Debug, thiserror::Error)]
23pub enum ImageError {
24 #[error("width or height must not be zero")]
25 InvalidDimensions,
26
27 #[error(transparent)]
28 BoundsCheck(#[from] BoundsCheckError),
29}
30
31impl Image<Vec<u8>> {
32 pub fn blank(format: PixelFormat, width: usize, height: usize, color: ColorInfo) -> Self {
33 Self {
34 format,
35 buffer: BufferKind::Whole(vec![0u8; format.buffer_size(width, height)]),
36 strides: format.packed_strides(width),
37 width,
38 height,
39 color,
40 }
41 }
42}
43
44impl<S> Image<S>
45where
46 Image<S>: ImageRef,
47{
48 pub fn from_buffer(
49 format: PixelFormat,
50 buffer: S,
51 strides: Option<Vec<usize>>,
52 width: usize,
53 height: usize,
54 color: ColorInfo,
55 ) -> Result<Self, ImageError> {
56 Self::new(
57 format,
58 BufferKind::Whole(buffer),
59 strides,
60 width,
61 height,
62 color,
63 )
64 }
65
66 pub fn from_planes(
67 format: PixelFormat,
68 planes: Vec<S>,
69 strides: Option<Vec<usize>>,
70 width: usize,
71 height: usize,
72 color: ColorInfo,
73 ) -> Result<Self, ImageError> {
74 Self::new(
75 format,
76 BufferKind::Split(planes),
77 strides,
78 width,
79 height,
80 color,
81 )
82 }
83
84 fn new(
85 format: PixelFormat,
86 buffer: BufferKind<S>,
87 strides: Option<Vec<usize>>,
88 width: usize,
89 height: usize,
90 color: ColorInfo,
91 ) -> Result<Self, ImageError> {
92 if width == 0 || height == 0 {
93 return Err(ImageError::InvalidDimensions);
94 }
95
96 let strides = strides.unwrap_or_else(|| format.packed_strides(width));
97
98 let this = Self {
99 format,
100 buffer,
101 strides,
102 width,
103 height,
104 color,
105 };
106
107 this.bounds_check()?;
108
109 Ok(this)
110 }
111
112 pub fn buffer(&self) -> &BufferKind<S> {
113 &self.buffer
114 }
115
116 pub fn into_buffer(self) -> BufferKind<S> {
117 self.buffer
118 }
119}
120
121unsafe impl<S: AsRef<[u8]>> ImageRef for Image<S> {
122 fn format(&self) -> PixelFormat {
123 self.format
124 }
125 fn width(&self) -> usize {
126 self.width
127 }
128 fn height(&self) -> usize {
129 self.height
130 }
131
132 fn planes(&self) -> Box<dyn Iterator<Item = (&[u8], usize)> + '_> {
133 match &self.buffer {
134 BufferKind::Whole(buffer) => Box::new(
135 infer(
136 self.format,
137 buffer.as_ref(),
138 self.width,
139 self.height,
140 Some(&self.strides),
141 )
142 .zip(self.strides.iter().copied()),
143 ),
144 BufferKind::Split(planes) => Box::new(
145 planes
146 .iter()
147 .map(|p| p.as_ref())
148 .zip(self.strides.iter().copied()),
149 ),
150 }
151 }
152 fn color(&self) -> ColorInfo {
153 self.color
154 }
155}
156
157unsafe impl<S: AsRef<[u8]> + AsMut<[u8]>> ImageMut for Image<S> {
158 fn planes_mut(&mut self) -> Box<dyn Iterator<Item = (&mut [u8], usize)> + '_> {
159 match &mut self.buffer {
160 BufferKind::Whole(buffer) => Box::new(
161 infer(
162 self.format,
163 buffer.as_mut(),
164 self.width,
165 self.height,
166 Some(&self.strides),
167 )
168 .zip(self.strides.iter().copied()),
169 ),
170 BufferKind::Split(planes) => Box::new(
171 planes
172 .iter_mut()
173 .map(|plane| plane.as_mut())
174 .zip(self.strides.iter().copied()),
175 ),
176 }
177 }
178}