1pub trait RGBSource {
6 #[must_use]
8 fn dimensions_i32(&self) -> (i32, i32) {
9 let (w, h) = self.dimensions();
10 (w as i32, h as i32)
11 }
12
13 #[must_use]
15 fn dimensions(&self) -> (usize, usize);
16
17 #[must_use]
20 fn pixel_f32(&self, x: usize, y: usize) -> (f32, f32, f32);
21}
22
23pub trait RGB8Source: RGBSource {
28 #[must_use]
33 fn dimensions_padded(&self) -> (usize, usize);
34
35 #[must_use]
37 fn rgb8_data(&self) -> &[u8];
38}
39
40#[derive(Copy, Clone, Debug)]
44#[must_use]
45pub struct RgbSliceU8<'a> {
46 data: &'a [u8],
47 dimensions: (usize, usize),
48}
49
50#[derive(Copy, Clone, Debug)]
52#[must_use]
53pub struct BgrSliceU8<'a> {
54 data: &'a [u8],
55 dimensions: (usize, usize),
56}
57
58#[derive(Copy, Clone, Debug)]
60#[must_use]
61pub struct RgbaSliceU8<'a> {
62 data: &'a [u8],
63 dimensions: (usize, usize),
64}
65
66#[derive(Copy, Clone, Debug)]
70#[must_use]
71pub struct RgbaSliceU32<'a> {
72 data: &'a [u32],
73 dimensions: (usize, usize),
74}
75
76#[derive(Copy, Clone, Debug)]
78#[must_use]
79pub struct BgraSliceU8<'a> {
80 data: &'a [u8],
81 dimensions: (usize, usize),
82}
83
84#[derive(Copy, Clone, Debug)]
88#[must_use]
89pub struct BgraSliceU32<'a> {
90 data: &'a [u32],
91 dimensions: (usize, usize),
92}
93
94#[derive(Copy, Clone, Debug)]
96#[must_use]
97pub struct AbgrSliceU8<'a> {
98 data: &'a [u8],
99 dimensions: (usize, usize),
100}
101
102#[derive(Copy, Clone, Debug)]
106#[must_use]
107pub struct AbgrSliceU32<'a> {
108 data: &'a [u32],
109 dimensions: (usize, usize),
110}
111
112#[derive(Copy, Clone, Debug)]
114#[must_use]
115pub struct ArgbSliceU8<'a> {
116 data: &'a [u8],
117 dimensions: (usize, usize),
118}
119
120#[derive(Copy, Clone, Debug)]
124#[must_use]
125pub struct ArgbSliceU32<'a> {
126 data: &'a [u32],
127 dimensions: (usize, usize),
128}
129
130macro_rules! impl_slice_wrapper_u8 {
131 ($t:ty, $stride:expr, $offsets:expr) => {
132 impl<'a> $t {
133 #[allow(unused)]
139 pub fn new(data: &'a [u8], dimensions: (usize, usize)) -> Self {
140 assert_eq!(data.len(), dimensions.0 * dimensions.1 * $stride);
141 assert_eq!(dimensions.0 % 2, 0, "width needs to be multiple of 2");
142 assert_eq!(dimensions.1 % 2, 0, "height needs to be a multiple of 2");
143
144 Self { data, dimensions }
145 }
146 }
147
148 impl<'a> RGBSource for $t {
149 fn dimensions(&self) -> (usize, usize) {
150 self.dimensions
151 }
152
153 fn pixel_f32(&self, x: usize, y: usize) -> (f32, f32, f32) {
154 let base_pos = (x + y * self.dimensions.0) * $stride;
155 (
156 self.data[base_pos + $offsets[0]].into(),
157 self.data[base_pos + $offsets[1]].into(),
158 self.data[base_pos + $offsets[2]].into(),
159 )
160 }
161 }
162 };
163}
164
165macro_rules! impl_slice_wrapper_u32 {
166 ($t:ty, $offsets:expr) => {
167 impl<'a> $t {
168 #[allow(unused)]
174 pub fn new(data: &'a [u32], dimensions: (usize, usize)) -> Self {
175 assert_eq!(data.len(), dimensions.0 * dimensions.1);
176 assert_eq!(dimensions.0 % 2, 0, "width needs to be multiple of 2");
177 assert_eq!(dimensions.1 % 2, 0, "height needs to be a multiple of 2");
178
179 Self { data, dimensions }
180 }
181 }
182
183 impl<'a> RGBSource for $t {
184 fn dimensions(&self) -> (usize, usize) {
185 self.dimensions
186 }
187
188 fn pixel_f32(&self, x: usize, y: usize) -> (f32, f32, f32) {
189 let px = self.data[x + y * self.dimensions.0];
190 (
191 ((px >> $offsets[0]) & 0xFF) as f32,
192 ((px >> $offsets[1]) & 0xFF) as f32,
193 ((px >> $offsets[2]) & 0xFF) as f32,
194 )
195 }
196 }
197 };
198}
199
200impl_slice_wrapper_u8!(RgbSliceU8<'a>, 3, [0, 1, 2]);
201impl_slice_wrapper_u8!(RgbaSliceU8<'a>, 4, [0, 1, 2]);
202impl_slice_wrapper_u8!(BgrSliceU8<'a>, 3, [2, 1, 0]);
203impl_slice_wrapper_u8!(BgraSliceU8<'a>, 4, [2, 1, 0]);
204impl_slice_wrapper_u8!(ArgbSliceU8<'a>, 4, [1, 2, 3]);
205impl_slice_wrapper_u8!(AbgrSliceU8<'a>, 4, [3, 2, 1]);
206
207impl_slice_wrapper_u32!(RgbaSliceU32<'a>, [24, 16, 8]);
208impl_slice_wrapper_u32!(BgraSliceU32<'a>, [8, 16, 24]);
209impl_slice_wrapper_u32!(AbgrSliceU32<'a>, [0, 8, 16]);
210impl_slice_wrapper_u32!(ArgbSliceU32<'a>, [16, 8, 0]);
211
212impl RGB8Source for RgbSliceU8<'_> {
213 fn dimensions_padded(&self) -> (usize, usize) {
214 self.dimensions()
215 }
216
217 fn rgb8_data(&self) -> &[u8] {
218 self.data
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::{AbgrSliceU32, ArgbSliceU32, BgrSliceU8, BgraSliceU32, RGBSource, RgbSliceU8, RgbaSliceU32};
225
226 #[test]
227 fn rgb_slice_4x4() {
228 let vec: Vec<u8> = (0..4 * 4 * 3).collect();
229 let slice = RgbSliceU8::new(&vec, (4, 4));
230 assert_eq!(slice.pixel_f32(0, 0), (0., 1., 2.));
231 assert_eq!(slice.pixel_f32(1, 0), (3., 4., 5.));
232 assert_eq!(slice.pixel_f32(2, 0), (6., 7., 8.));
233 assert_eq!(slice.pixel_f32(0, 1), (12., 13., 14.));
234 assert_eq!(slice.pixel_f32(1, 1), (15., 16., 17.));
235 assert_eq!(slice.pixel_f32(2, 1), (18., 19., 20.));
236 assert_eq!(slice.pixel_f32(0, 2), (24., 25., 26.));
237 assert_eq!(slice.pixel_f32(1, 2), (27., 28., 29.));
238 assert_eq!(slice.pixel_f32(2, 2), (30., 31., 32.));
239 }
240
241 #[test]
242 fn bgr_slice_4x4() {
243 let vec: Vec<u8> = (0..4 * 4 * 3).collect();
244 let slice = BgrSliceU8::new(&vec, (4, 4));
245 assert_eq!(slice.pixel_f32(0, 0), (2., 1., 0.));
246 assert_eq!(slice.pixel_f32(1, 0), (5., 4., 3.));
247 assert_eq!(slice.pixel_f32(2, 0), (8., 7., 6.));
248 assert_eq!(slice.pixel_f32(0, 1), (14.0, 13.0, 12.0));
249 assert_eq!(slice.pixel_f32(1, 1), (17.0, 16.0, 15.0));
250 assert_eq!(slice.pixel_f32(2, 1), (20.0, 19.0, 18.0));
251 assert_eq!(slice.pixel_f32(0, 2), (26.0, 25.0, 24.0));
252 assert_eq!(slice.pixel_f32(1, 2), (29.0, 28.0, 27.0));
253 assert_eq!(slice.pixel_f32(2, 2), (32.0, 31.0, 30.0));
254 }
255
256 #[test]
257 fn rgba_slice_2x2() {
258 let data: [u32; 5] = [0xFF000102, 0xFF010002, 0xFF000201, 0xFF020001, 0xAABBCCDD];
259 let slice = RgbaSliceU32::new(&data[1..], (2, 2));
260 assert_eq!(slice.pixel_f32(0, 0), (255., 1., 0.));
261 assert_eq!(slice.pixel_f32(1, 0), (255., 0., 2.));
262 assert_eq!(slice.pixel_f32(0, 1), (255., 2., 0.));
263 assert_eq!(slice.pixel_f32(1, 1), (170., 187., 204.));
264 }
265
266 #[test]
267 fn argb_slice_2x2() {
268 let data: [u32; 5] = [0xFF000102, 0xFF010002, 0xFF000201, 0xFF020001, 0xAABBCCDD];
269 let slice = ArgbSliceU32::new(&data[1..], (2, 2));
270 assert_eq!(slice.pixel_f32(0, 0), (1., 0., 2.));
271 assert_eq!(slice.pixel_f32(1, 0), (0., 2., 1.));
272 assert_eq!(slice.pixel_f32(0, 1), (2., 0., 1.));
273 assert_eq!(slice.pixel_f32(1, 1), (187., 204., 221.));
274 }
275
276 #[test]
277 fn bgra_slice_2x2() {
278 let data: [u32; 5] = [0xFF000102, 0xFF010002, 0xFF000201, 0xFF020001, 0xAABBCCDD];
279 let slice = BgraSliceU32::new(&data[1..], (2, 2));
280 assert_eq!(slice.pixel_f32(0, 0), (0., 1., 255.));
281 assert_eq!(slice.pixel_f32(1, 0), (2., 0., 255.));
282 assert_eq!(slice.pixel_f32(0, 1), (0., 2., 255.));
283 assert_eq!(slice.pixel_f32(1, 1), (204., 187., 170.));
284 }
285
286 #[test]
287 fn abgr_slice_2x2() {
288 let data: [u32; 5] = [0xFF000102, 0xFF010002, 0xFF000201, 0xFF020001, 0xAABBCCDD];
289 let slice = AbgrSliceU32::new(&data[1..], (2, 2));
290 assert_eq!(slice.pixel_f32(0, 0), (2., 0., 1.));
291 assert_eq!(slice.pixel_f32(1, 0), (1., 2., 0.));
292 assert_eq!(slice.pixel_f32(0, 1), (1., 0., 2.));
293 assert_eq!(slice.pixel_f32(1, 1), (221., 204., 187.));
294 }
295}