1 | //! Contiguous iterator. |
2 | |
3 | use crate::{ |
4 | geometry::{Point, Size}, |
5 | pixelcolor::PixelColor, |
6 | primitives::{rectangle, PointsIter, Rectangle}, |
7 | Pixel, |
8 | }; |
9 | use core::iter::Zip; |
10 | |
11 | /// Converts a contiguous iterator into a pixel iterator. |
12 | #[derive (Debug)] |
13 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
14 | pub struct IntoPixels<I> |
15 | where |
16 | I: Iterator, |
17 | I::Item: PixelColor, |
18 | { |
19 | iter: Zip<rectangle::Points, I>, |
20 | } |
21 | |
22 | impl<I> IntoPixels<I> |
23 | where |
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 | |
34 | impl<I> Iterator for IntoPixels<I> |
35 | where |
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: Point, c: impl PixelColor)| Pixel(p, c)) |
44 | } |
45 | } |
46 | |
47 | /// Crops a part of the underlying iterator. |
48 | #[derive (Debug)] |
49 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
50 | pub(crate) struct Cropped<I> |
51 | where |
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 | |
63 | impl<I> Cropped<I> |
64 | where |
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 = Rectangle::new(top_left:Point::zero(), size).intersection(crop_area); |
70 | |
71 | let initial_skip: usize = |
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 | |
88 | impl<I> Iterator for Cropped<I> |
89 | where |
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)] |
118 | mod 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, // |
133 | 66, 67, 68, 69, // |
134 | 82, 83, 84, 85, // |
135 | ]; |
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, // |
166 | 190, 191, // |
167 | 206, 207, // |
168 | 222, 223, // |
169 | ]; |
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 | } |
177 | |