1use {
2 super::{
3 geom::{Point, Rect, Size},
4 num::Zero,
5 },
6 std::{mem, ops::{Index, IndexMut}},
7};
8
9#[derive(Clone, Debug, Eq, Hash, PartialEq)]
10pub struct Image<T> {
11 size: Size<usize>,
12 pixels: Vec<T>,
13}
14
15impl<T> Image<T> {
16 pub fn new(size: Size<usize>) -> Self
17 where
18 T: Clone + Default,
19 {
20 Self {
21 size,
22 pixels: vec![Default::default(); size.width * size.height],
23 }
24 }
25
26 pub fn from_size_and_pixels(size: Size<usize>, pixels: Vec<T>) -> Self {
27 assert_eq!(size.width * size.height, pixels.len());
28 Self { size, pixels }
29 }
30
31 pub fn into_pixels(self) -> Vec<T> {
32 self.pixels
33 }
34
35 pub fn is_empty(&self) -> bool {
36 self.size() == Size::ZERO
37 }
38
39 pub fn size(&self) -> Size<usize> {
40 self.size
41 }
42
43 pub fn as_pixels(&self) -> &[T] {
44 &self.pixels
45 }
46
47 pub fn as_mut_pixels(&mut self) -> &mut [T] {
48 &mut self.pixels
49 }
50
51 pub unsafe fn replace_pixels(&mut self, pixels: Vec<T>) -> Vec<T> {
52 mem::replace(&mut self.pixels, pixels)
53 }
54
55 pub fn subimage(&self, rect: Rect<usize>) -> Subimage<'_, T> {
56 assert!(
57 Rect::from(self.size).contains_rect(rect),
58 "rect is out of bounds"
59 );
60 Subimage {
61 image: self,
62 bounds: rect,
63 }
64 }
65
66 pub fn subimage_mut(&mut self, rect: Rect<usize>) -> SubimageMut<'_, T> {
67 assert!(
68 Rect::from(self.size()).contains_rect(rect),
69 "rect {:?} is out of bounds (should fit in rect {:?})",
70 rect,
71 Rect::from(self.size())
72 );
73 SubimageMut {
74 image: self,
75 bounds: rect,
76 }
77 }
78}
79
80impl<T> Index<Point<usize>> for Image<T> {
81 type Output = T;
82
83 fn index(&self, point: Point<usize>) -> &Self::Output {
84 assert!(
85 Rect::from(self.size()).contains_point(point),
86 "point is out of bounds"
87 );
88 &self.pixels[point.y * self.size.width + point.x]
89 }
90}
91
92impl<T> IndexMut<Point<usize>> for Image<T> {
93 fn index_mut(&mut self, point: Point<usize>) -> &mut Self::Output {
94 assert!(
95 Rect::from(self.size()).contains_point(point),
96 "point is out of bounds"
97 );
98 &mut self.pixels[point.y * self.size.width + point.x]
99 }
100}
101
102#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
103pub struct Subimage<'a, T> {
104 image: &'a Image<T>,
105 bounds: Rect<usize>,
106}
107
108impl<'a, T> Subimage<'a, T> {
109 pub fn is_empty(&self) -> bool {
110 self.bounds().is_empty()
111 }
112
113 pub fn size(&self) -> Size<usize> {
114 self.bounds().size
115 }
116
117 pub fn bounds(&self) -> Rect<usize> {
118 self.bounds
119 }
120
121 pub fn to_image(&self) -> Image<T>
122 where
123 T: Copy,
124 {
125 let mut pixels = Vec::with_capacity(self.size().width * self.size().height);
126 for y in 0..self.size().height {
127 for x in 0..self.size().width {
128 pixels.push(self[Point::new(x, y)]);
129 }
130 }
131 Image::from_size_and_pixels(self.size(), pixels)
132 }
133}
134
135impl<'a, T> Index<Point<usize>> for Subimage<'a, T> {
136 type Output = T;
137
138 fn index(&self, point: Point<usize>) -> &Self::Output {
139 assert!(
140 Rect::from(self.bounds().size).contains_point(point),
141 "point is out of bounds"
142 );
143 &self.image[self.bounds.origin + Size::from(point)]
144 }
145}
146
147#[derive(Debug, Eq, Hash, PartialEq)]
148pub struct SubimageMut<'a, T> {
149 image: &'a mut Image<T>,
150 bounds: Rect<usize>,
151}
152
153impl<'a, T> SubimageMut<'a, T> {
154 pub fn is_empty(&self) -> bool {
155 self.bounds().is_empty()
156 }
157
158 pub fn size(&self) -> Size<usize> {
159 self.bounds().size
160 }
161
162 pub fn bounds(&self) -> Rect<usize> {
163 self.bounds
164 }
165
166 pub fn subimage_mut(self, rect: Rect<usize>) -> SubimageMut<'a, T> {
167 assert!(
168 Rect::from(self.size()).contains_rect(rect),
169 "rect {:?} is out of bounds (should fit in rect {:?})",
170 rect,
171 Rect::from(self.size())
172 );
173 SubimageMut {
174 image: self.image,
175 bounds: Rect::new(self.bounds.origin + Size::from(rect.origin), rect.size),
176 }
177 }
178}
179
180impl<'a, T> Index<Point<usize>> for SubimageMut<'a, T> {
181 type Output = T;
182
183 fn index(&self, point: Point<usize>) -> &Self::Output {
184 assert!(
185 Rect::from(self.bounds().size).contains_point(point),
186 "point is out of bounds"
187 );
188 &self.image[self.bounds.origin + Size::from(point)]
189 }
190}
191
192impl<'a, T> IndexMut<Point<usize>> for SubimageMut<'a, T> {
193 fn index_mut(&mut self, point: Point<usize>) -> &mut Self::Output {
194 assert!(
195 Rect::from(self.bounds().size).contains_point(point),
196 "point is out of bounds"
197 );
198 &mut self.image[self.bounds.origin + Size::from(point)]
199 }
200}
201
202#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
203#[repr(transparent)]
204pub struct R {
205 pub bits: u8,
206}
207
208impl R {
209 pub const fn new(r: u8) -> Self {
210 Self { bits: r }
211 }
212
213 pub fn r(self) -> u8 {
214 self.bits
215 }
216}
217
218#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
219#[repr(transparent)]
220pub struct Bgra {
221 pub bits: u32,
222}
223
224impl Bgra {
225 pub fn new(b: u8, g: u8, r: u8, a: u8) -> Self {
226 let b = u32::from(b);
227 let g = u32::from(g);
228 let r = u32::from(r);
229 let a = u32::from(a);
230 Self { bits: (a << 24) | (r << 16) | (g << 8) | b }
231 }
232
233 pub fn b(self) -> u8 {
234 (self.bits & 0xFF) as u8
235 }
236
237 pub fn g(self) -> u8 {
238 ((self.bits >> 8) & 0xFF) as u8
239 }
240
241 pub fn r(self) -> u8 {
242 ((self.bits >> 16) & 0xFF) as u8
243 }
244
245 pub fn a(self) -> u8 {
246 ((self.bits >> 24) & 0xFF) as u8
247 }
248}