embedded_graphics/image/
sub_image.rs1use crate::{
2 draw_target::DrawTarget,
3 geometry::{Dimensions, OriginDimensions},
4 image::ImageDrawable,
5 primitives::Rectangle,
6 transform::Transform,
7};
8
9#[derive(Debug)]
20#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
21pub struct SubImage<'a, T> {
22 parent: &'a T,
23 area: Rectangle,
24}
25
26impl<'a, T> SubImage<'a, T>
27where
28 T: ImageDrawable,
29{
30 pub(super) fn new(parent: &'a T, area: &Rectangle) -> Self {
31 let area = parent.bounding_box().intersection(area);
32
33 Self { parent, area }
34 }
35
36 pub(crate) const fn new_unchecked(parent: &'a T, area: Rectangle) -> Self {
37 Self { parent, area }
38 }
39}
40
41impl<T> OriginDimensions for SubImage<'_, T> {
42 fn size(&self) -> crate::prelude::Size {
43 self.area.size
44 }
45}
46
47impl<'a, T> ImageDrawable for SubImage<'a, T>
48where
49 T: ImageDrawable,
50{
51 type Color = T::Color;
52
53 fn draw<DT>(&self, target: &mut DT) -> Result<(), DT::Error>
54 where
55 DT: DrawTarget<Color = Self::Color>,
56 {
57 self.parent.draw_sub_image(target, &self.area)
58 }
59
60 fn draw_sub_image<DT>(&self, target: &mut DT, area: &Rectangle) -> Result<(), DT::Error>
61 where
62 DT: DrawTarget<Color = Self::Color>,
63 {
64 let area = area.translate(self.area.top_left);
65
66 self.parent.draw_sub_image(target, &area)
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use crate::{
74 geometry::{Point, Size},
75 image::ImageDrawableExt,
76 mock_display::MockDisplay,
77 pixelcolor::BinaryColor,
78 };
79
80 struct MockImageDrawable {
81 expected_area: Rectangle,
82 }
83
84 impl ImageDrawable for MockImageDrawable {
85 type Color = BinaryColor;
86
87 fn draw<DT>(&self, _target: &mut DT) -> Result<(), DT::Error>
88 where
89 DT: DrawTarget<Color = BinaryColor>,
90 {
91 panic!("draw shouldn't have been called on MockImageDrawable")
92 }
93
94 fn draw_sub_image<DT>(&self, _target: &mut DT, area: &Rectangle) -> Result<(), DT::Error>
95 where
96 DT: DrawTarget<Color = BinaryColor>,
97 {
98 assert_eq!(area, &self.expected_area);
99
100 Ok(())
101 }
102 }
103
104 impl OriginDimensions for MockImageDrawable {
105 fn size(&self) -> Size {
106 Size::new(8, 10)
107 }
108 }
109
110 #[test]
111 fn sub_image() {
112 let area = Rectangle::new(Point::new(2, 3), Size::new(3, 4));
113
114 let image = MockImageDrawable {
115 expected_area: area,
116 };
117
118 let mut display = MockDisplay::new();
119 image.sub_image(&area).draw(&mut display).unwrap();
120 }
121
122 #[test]
123 fn area_larger_than_parent() {
124 let area = Rectangle::new(Point::new(-5, -5), Size::new(20, 20));
125
126 let image = MockImageDrawable {
127 expected_area: Rectangle::new(Point::zero(), Size::new(8, 10)),
128 };
129
130 let mut display = MockDisplay::new();
131 image.sub_image(&area).draw(&mut display).unwrap();
132 }
133
134 #[test]
135 fn sub_image_of_sub_image() {
136 let area1 = Rectangle::new(Point::new(2, 3), Size::new(3, 4));
137 let area2 = Rectangle::new(Point::new(1, 1), Size::new(2, 2));
138
139 let image = MockImageDrawable {
140 expected_area: Rectangle::new(area1.top_left + area2.top_left, area2.size),
141 };
142
143 let mut display = MockDisplay::new();
144 image
145 .sub_image(&area1)
146 .sub_image(&area2)
147 .draw(&mut display)
148 .unwrap();
149 }
150
151 #[test]
152 fn sub_image_of_sub_image_area_larger_than_parent() {
153 let area1 = Rectangle::new(Point::new(2, 3), Size::new(3, 4));
154 let area2 = Rectangle::new(Point::new(-10, -10), Size::new(20, 20));
155
156 let image = MockImageDrawable {
157 expected_area: area1,
158 };
159
160 let mut display = MockDisplay::new();
161 image
162 .sub_image(&area1)
163 .sub_image(&area2)
164 .draw(&mut display)
165 .unwrap();
166 }
167}