embedded_graphics/iterator/
contiguous.rs1use crate::{
4 geometry::{Point, Size},
5 pixelcolor::PixelColor,
6 primitives::{rectangle, PointsIter, Rectangle},
7 Pixel,
8};
9use core::iter::Zip;
10
11#[derive(Debug)]
13#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
14pub struct IntoPixels<I>
15where
16 I: Iterator,
17 I::Item: PixelColor,
18{
19 iter: Zip<rectangle::Points, I>,
20}
21
22impl<I> IntoPixels<I>
23where
24 I: Iterator,
25 I::Item: PixelColor,
26{
27 pub(super) fn new(iter: I, bounding_box: Rectangle) -> Self {
28 Self {
29 iter: bounding_box.points().zip(iter),
30 }
31 }
32}
33
34impl<I> Iterator for IntoPixels<I>
35where
36 I: Iterator,
37 I::Item: PixelColor,
38{
39 type Item = Pixel<I::Item>;
40
41 #[inline]
42 fn next(&mut self) -> Option<Self::Item> {
43 self.iter.next().map(|(p, c)| Pixel(p, c))
44 }
45}
46
47#[derive(Debug)]
49#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
50pub(crate) struct Cropped<I>
51where
52 I: Iterator,
53 I::Item: PixelColor,
54{
55 iter: I,
56
57 x: u32,
58 y: u32,
59 size: Size,
60 row_skip: usize,
61}
62
63impl<I> Cropped<I>
64where
65 I: Iterator,
66 I::Item: PixelColor,
67{
68 pub(crate) fn new(mut iter: I, size: Size, crop_area: &Rectangle) -> Self {
69 let crop_area = Rectangle::new(Point::zero(), size).intersection(crop_area);
70
71 let initial_skip =
72 crop_area.top_left.y as usize * size.width as usize + crop_area.top_left.x as usize;
73
74 if initial_skip > 0 {
75 iter.nth(initial_skip - 1);
76 }
77
78 Self {
79 iter,
80 x: 0,
81 y: 0,
82 size: crop_area.size,
83 row_skip: (size.width - crop_area.size.width) as usize,
84 }
85 }
86}
87
88impl<I> Iterator for Cropped<I>
89where
90 I: Iterator,
91 I::Item: PixelColor,
92{
93 type Item = I::Item;
94
95 fn next(&mut self) -> Option<Self::Item> {
96 if self.y >= self.size.height || self.size.width == 0 {
97 return None;
98 }
99
100 if self.x < self.size.width {
101 self.x += 1;
102
103 self.iter.next()
104 } else {
105 self.x = 1;
106 self.y += 1;
107
108 if self.y < self.size.height {
109 self.iter.nth(self.row_skip)
110 } else {
111 None
112 }
113 }
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120 use crate::pixelcolor::Gray8;
121
122 #[test]
123 fn cropped() {
124 let parent = (0..=255).map(Gray8::new);
125 let parent_size = Size::new(16, 16);
126
127 let crop_area = Rectangle::new(Point::new(2, 3), Size::new(4, 3));
128
129 let mut cropped_iter = Cropped::new(parent, parent_size, &crop_area);
130
131 let expected = &[
132 50, 51, 52, 53, 66, 67, 68, 69, 82, 83, 84, 85, ];
136
137 for value in expected {
138 assert_eq!(cropped_iter.next(), Some(Gray8::new(*value)));
139 }
140 assert_eq!(cropped_iter.next(), None);
141 }
142
143 #[test]
144 fn cropped_empty() {
145 let parent = (0..=255).map(Gray8::new);
146 let parent_size = Size::new(16, 16);
147
148 let crop_area = Rectangle::zero();
149
150 let mut cropped_iter = Cropped::new(parent, parent_size, &crop_area);
151
152 assert_eq!(cropped_iter.next(), None);
153 }
154
155 #[test]
156 fn cropped_overlapping() {
157 let parent = (0..=255).map(Gray8::new);
158 let parent_size = Size::new(16, 16);
159
160 let crop_area = Rectangle::new(Point::new(14, 10), Size::new(4, 4));
161
162 let mut cropped_iter = Cropped::new(parent, parent_size, &crop_area);
163
164 let expected = &[
165 174, 175, 190, 191, 206, 207, 222, 223, ];
170
171 for value in expected {
172 assert_eq!(cropped_iter.next(), Some(Gray8::new(*value)));
173 }
174 assert_eq!(cropped_iter.next(), None);
175 }
176}