1use core::{iter, slice};
2
3use embedded_graphics::{
4 iterator::raw::RawDataSlice,
5 pixelcolor::raw::{LittleEndian, RawU1, RawU16, RawU24, RawU32, RawU4, RawU8},
6 prelude::*,
7 primitives::{rectangle, Rectangle},
8};
9
10use crate::{
11 header::{Bpp, RowOrder},
12 raw_bmp::RawBmp,
13};
14
15/// Iterator over raw pixel colors.
16#[allow(missing_debug_implementations)]
17pub struct RawColors<'a, R>
18where
19 RawDataSlice<'a, R, LittleEndian>: IntoIterator<Item = R>,
20{
21 rows: slice::ChunksExact<'a, u8>,
22 row_order: RowOrder,
23 current_row: iter::Take<<RawDataSlice<'a, R, LittleEndian> as IntoIterator>::IntoIter>,
24 width: usize,
25}
26
27impl<'a, R> RawColors<'a, R>
28where
29 RawDataSlice<'a, R, LittleEndian>: IntoIterator<Item = R>,
30{
31 pub(crate) fn new(raw_bmp: &'a RawBmp<'a>) -> Self {
32 let header: &Header = raw_bmp.header();
33
34 let width: usize = header.image_size.width as usize;
35
36 Self {
37 rows: raw_bmp.image_data().chunks_exact(chunk_size:header.bytes_per_row()),
38 row_order: raw_bmp.header().row_order,
39 current_row: RawDataSlice::new(&[]).into_iter().take(0),
40 width,
41 }
42 }
43}
44
45impl<'a, R> Iterator for RawColors<'a, R>
46where
47 RawDataSlice<'a, R, LittleEndian>: IntoIterator<Item = R>,
48{
49 type Item = R;
50
51 fn next(&mut self) -> Option<Self::Item> {
52 self.current_row.next().or_else(|| {
53 let next_row: &'a [u8] = match self.row_order {
54 RowOrder::TopDown => self.rows.next(),
55 RowOrder::BottomUp => self.rows.next_back(),
56 }?;
57
58 self.current_row = RawDataSlice::new(data:next_row).into_iter().take(self.width);
59
60 self.current_row.next()
61 })
62 }
63}
64
65enum DynamicRawColors<'a> {
66 Bpp1(RawColors<'a, RawU1>),
67 Bpp4(RawColors<'a, RawU4>),
68 Bpp8(RawColors<'a, RawU8>),
69 Bpp16(RawColors<'a, RawU16>),
70 Bpp24(RawColors<'a, RawU24>),
71 Bpp32(RawColors<'a, RawU32>),
72}
73
74impl<'a> DynamicRawColors<'a> {
75 pub fn new(raw_bmp: &'a RawBmp<'a>) -> Self {
76 match raw_bmp.header().bpp {
77 Bpp::Bits1 => DynamicRawColors::Bpp1(RawColors::new(raw_bmp)),
78 Bpp::Bits4 => DynamicRawColors::Bpp4(RawColors::new(raw_bmp)),
79 Bpp::Bits8 => DynamicRawColors::Bpp8(RawColors::new(raw_bmp)),
80 Bpp::Bits16 => DynamicRawColors::Bpp16(RawColors::new(raw_bmp)),
81 Bpp::Bits24 => DynamicRawColors::Bpp24(RawColors::new(raw_bmp)),
82 Bpp::Bits32 => DynamicRawColors::Bpp32(RawColors::new(raw_bmp)),
83 }
84 }
85}
86
87/// Iterator over individual BMP pixels.
88///
89/// Each pixel is returned as a `u32` regardless of the bit depth of the source image.
90#[allow(missing_debug_implementations)]
91pub struct RawPixels<'a> {
92 colors: DynamicRawColors<'a>,
93 points: rectangle::Points,
94}
95
96impl<'a> RawPixels<'a> {
97 pub(crate) fn new(raw_bmp: &'a RawBmp<'a>) -> Self {
98 Self {
99 colors: DynamicRawColors::new(raw_bmp),
100 points: Rectangle::new(top_left:Point::zero(), raw_bmp.header().image_size).points(),
101 }
102 }
103}
104
105impl Iterator for RawPixels<'_> {
106 type Item = RawPixel;
107
108 fn next(&mut self) -> Option<Self::Item> {
109 let color: u32 = match &mut self.colors {
110 DynamicRawColors::Bpp1(colors: &mut RawColors<'_, RawU1>) => colors.next().map(|r: RawU1| u32::from(r.into_inner())),
111 DynamicRawColors::Bpp4(colors: &mut RawColors<'_, RawU4>) => colors.next().map(|r: RawU4| u32::from(r.into_inner())),
112 DynamicRawColors::Bpp8(colors: &mut RawColors<'_, RawU8>) => colors.next().map(|r: RawU8| u32::from(r.into_inner())),
113 DynamicRawColors::Bpp16(colors: &mut RawColors<'_, RawU16>) => colors.next().map(|r: RawU16| u32::from(r.into_inner())),
114 DynamicRawColors::Bpp24(colors: &mut RawColors<'_, RawU24>) => colors.next().map(|r: RawU24| u32::from(r.into_inner())),
115 DynamicRawColors::Bpp32(colors: &mut RawColors<'_, RawU32>) => colors.next().map(|r: RawU32| u32::from(r.into_inner())),
116 }?;
117
118 let position: Point = self.points.next()?;
119
120 Some(RawPixel { position, color })
121 }
122}
123
124/// Pixel with raw pixel color stored as a `u32`.
125#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)]
126pub struct RawPixel {
127 /// The position relative to the top left corner of the image.
128 pub position: Point,
129
130 /// The raw pixel color.
131 pub color: u32,
132}
133
134impl RawPixel {
135 /// Creates a new raw pixel.
136 pub const fn new(position: Point, color: u32) -> Self {
137 Self { position, color }
138 }
139}
140