embedded_graphics_transform/
lib.rs1#![no_std]
25
26use core::ops::{Deref, DerefMut};
27use embedded_graphics_core::{prelude::*, primitives::Rectangle};
28
29#[cfg(test)]
30mod tests;
31
32macro_rules! xform_type {
33 ($inner:ident , ) => { $inner };
34 ($inner:ident , $xform: ident $($rest:ident)*) => {
35 r#impl::$xform < xform_type!($inner, $($rest)*) >
36 };
37}
38
39macro_rules! xform_new {
40 ($inner:ident , ) => {
41 $inner
42 };
43 ($inner:ident , $xform:ident $($rest:ident)*) => {
44 r#impl::$xform::new(xform_new!($inner, $($rest)*))
45 };
46}
47
48macro_rules! impl_as_ref {
49 ($_asref:ident, $expr:expr, ) => { $expr };
50
51 ($asref:ident, $expr:expr, $xform:ident $($rest:ident)*) => {
52 impl_as_ref!($asref, r#impl::$xform::$asref($expr), $($rest)*)
53 };
54}
55
56macro_rules! impl_xform {
57 ($($(#[$attr:meta])* $name:ident : $($xforms:ident)* ; )*) => {
58 $(
59 $(#[$attr])*
60 pub struct $name<D> {
61 target: xform_type!(D, $($xforms)*)
62 }
63
64 impl<D> $name<D> {
65 #[allow(clippy::redundant_field_names)]
67 pub fn new(target: D) -> Self {
68 $name {
69 target: xform_new!(target, $($xforms)*)
70 }
71 }
72
73 pub fn into_inner(self) -> D {
75 impl_as_ref!(into_inner, self.target, $($xforms)*)
76 }
77 }
78
79 impl<D> Deref for $name<D> {
80 type Target = D;
81
82 fn deref(&self) -> &D {
83 self.as_ref()
84 }
85 }
86
87 impl<D> DerefMut for $name<D> {
88 fn deref_mut(&mut self) -> &mut D {
89 self.as_mut()
90 }
91 }
92
93 impl<D> AsRef<D> for $name<D> {
94 #[inline]
95 fn as_ref(&self) -> &D {
96 impl_as_ref!(as_ref, &self.target, $($xforms)*)
97 }
98 }
99
100 impl<D> AsMut<D> for $name<D> {
101 #[inline]
102 fn as_mut(&mut self) -> &mut D {
103 impl_as_ref!(as_mut, &mut self.target, $($xforms)*)
104 }
105 }
106
107 impl<D: Dimensions> Dimensions for $name<D> {
108 #[inline]
109 fn bounding_box(&self) -> Rectangle {
110 self.target.bounding_box()
111 }
112 }
113
114 impl<D: DrawTarget> DrawTarget for $name<D> {
115 type Color = D::Color;
116 type Error = D::Error;
117
118 #[inline]
119 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
120 where
121 I: IntoIterator<Item = Pixel<Self::Color>>,
122 {
123 self.target.draw_iter(pixels)
124 }
125
126 #[inline]
127 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
128 where
129 I: IntoIterator<Item = Self::Color>,
130 {
131 self.target.fill_contiguous(area, colors)
132 }
133
134 #[inline]
135 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
136 self.target.fill_solid(area, color)
137 }
138
139 #[inline]
140 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
141 self.target.clear(color)
142 }
143 }
144 )*
145 }
146}
147
148impl_xform! {
151 Rotate0: ;
153 Rotate90: MirrorY TransposeXY;
155 Rotate270: TransposeXY MirrorY;
157 Rotate180: MirrorX MirrorY;
159
160 Transpose: TransposeXY;
162 FlipX: MirrorX;
164 FlipY: MirrorY;
166}
167
168#[derive(Debug, Clone, Copy, Eq, PartialEq)]
170pub enum Rotation {
171 Rotate0,
173 Rotate90,
175 Rotate180,
177 Rotate270,
179}
180
181enum RotateInner<D> {
182 Rotate0(Rotate0<D>),
183 Rotate90(Rotate90<D>),
184 Rotate180(Rotate180<D>),
185 Rotate270(Rotate270<D>),
186}
187
188pub struct Rotate<D> {
196 target: RotateInner<D>,
197}
198
199macro_rules! rotate_impl {
200 (& $rot:expr, $func:ident ( $($args:expr),* $(,)?)) => {
201 match &$rot.target {
202 RotateInner::Rotate0(inner) => inner.$func($($args),*),
203 RotateInner::Rotate90(inner) => inner.$func($($args),*),
204 RotateInner::Rotate180(inner) => inner.$func($($args),*),
205 RotateInner::Rotate270(inner) => inner.$func($($args),*),
206 }
207 };
208 (&mut $rot:expr, $func:ident ( $($args:expr),* $(,)?)) => {
209 match &mut $rot.target {
210 RotateInner::Rotate0(inner) => inner.$func($($args),*),
211 RotateInner::Rotate90(inner) => inner.$func($($args),*),
212 RotateInner::Rotate180(inner) => inner.$func($($args),*),
213 RotateInner::Rotate270(inner) => inner.$func($($args),*),
214 }
215 };
216 ($rot:expr, $func:ident ( $($args:expr),* $(,)?)) => {
217 match $rot.target {
218 RotateInner::Rotate0(inner) => inner.$func($($args),*),
219 RotateInner::Rotate90(inner) => inner.$func($($args),*),
220 RotateInner::Rotate180(inner) => inner.$func($($args),*),
221 RotateInner::Rotate270(inner) => inner.$func($($args),*),
222 }
223 };
224}
225
226impl<D> Rotate<D> {
227 pub fn new(rot: Rotation, target: D) -> Self {
229 let target = match rot {
230 Rotation::Rotate0 => RotateInner::Rotate0(Rotate0::new(target)),
231 Rotation::Rotate90 => RotateInner::Rotate90(Rotate90::new(target)),
232 Rotation::Rotate180 => RotateInner::Rotate180(Rotate180::new(target)),
233 Rotation::Rotate270 => RotateInner::Rotate270(Rotate270::new(target)),
234 };
235 Rotate { target }
236 }
237
238 pub fn into_inner(self) -> D {
240 rotate_impl!(self, into_inner())
241 }
242}
243
244impl<D> Deref for Rotate<D> {
245 type Target = D;
246
247 fn deref(&self) -> &D {
248 self.as_ref()
249 }
250}
251
252impl<D> DerefMut for Rotate<D> {
253 fn deref_mut(&mut self) -> &mut D {
254 self.as_mut()
255 }
256}
257
258impl<D> AsRef<D> for Rotate<D> {
259 fn as_ref(&self) -> &D {
260 rotate_impl!(&self, as_ref())
261 }
262}
263
264impl<D> AsMut<D> for Rotate<D> {
265 fn as_mut(&mut self) -> &mut D {
266 rotate_impl!(&mut self, as_mut())
267 }
268}
269
270impl<D: Dimensions> Dimensions for Rotate<D> {
271 fn bounding_box(&self) -> Rectangle {
272 rotate_impl!(&self, bounding_box())
273 }
274}
275
276impl<D: DrawTarget> DrawTarget for Rotate<D> {
277 type Color = D::Color;
278 type Error = D::Error;
279
280 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
281 where
282 I: IntoIterator<Item = Pixel<Self::Color>>,
283 {
284 rotate_impl!(&mut self, draw_iter(pixels))
285 }
286
287 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
288 where
289 I: IntoIterator<Item = Self::Color>,
290 {
291 rotate_impl!(&mut self, fill_contiguous(area, colors))
292 }
293
294 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
295 rotate_impl!(&mut self, fill_solid(area, color))
296 }
297
298 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
299 rotate_impl!(&mut self, clear(color))
300 }
301}
302
303mod r#impl {
304 use embedded_graphics_core::{prelude::*, primitives::Rectangle};
305
306 pub(crate) trait Transpose {
307 fn transpose(self) -> Self;
308 }
309
310 impl Transpose for Point {
311 #[inline]
312 fn transpose(self) -> Point {
313 Point {
314 x: self.y,
315 y: self.x,
316 }
317 }
318 }
319
320 impl Transpose for Size {
321 #[inline]
322 fn transpose(self) -> Size {
323 Size {
324 width: self.height,
325 height: self.width,
326 }
327 }
328 }
329
330 impl Transpose for Rectangle {
331 #[inline]
332 fn transpose(self) -> Rectangle {
333 Rectangle {
334 top_left: self.top_left.transpose(),
335 size: self.size.transpose(),
336 }
337 }
338 }
339
340 pub(crate) struct TransposeXY<D> {
341 target: D,
342 }
343
344 impl<D> TransposeXY<D> {
345 pub(crate) fn new(target: D) -> Self {
346 TransposeXY { target }
347 }
348
349 pub(crate) fn into_inner(self) -> D {
350 self.target
351 }
352 }
353
354 impl<D> AsRef<D> for TransposeXY<D> {
355 fn as_ref(&self) -> &D {
356 &self.target
357 }
358 }
359
360 impl<D> AsMut<D> for TransposeXY<D> {
361 fn as_mut(&mut self) -> &mut D {
362 &mut self.target
363 }
364 }
365
366 impl<D: Dimensions> Dimensions for TransposeXY<D> {
367 fn bounding_box(&self) -> Rectangle {
368 self.target.bounding_box().transpose()
369 }
370 }
371
372 impl<D: DrawTarget> DrawTarget for TransposeXY<D> {
373 type Color = D::Color;
374 type Error = D::Error;
375
376 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
377 where
378 I: IntoIterator<Item = Pixel<Self::Color>>,
379 {
380 self.target.draw_iter(
381 pixels
382 .into_iter()
383 .map(|Pixel(loc, col)| Pixel(loc.transpose(), col)),
384 )
385 }
386
387 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
388 let area = area.transpose();
389 self.target.fill_solid(&area, color)
390 }
391
392 #[inline]
393 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
394 self.target.clear(color)
395 }
396 }
397
398 pub(crate) struct MirrorX<D> {
399 target: D,
400 }
401
402 impl<D> MirrorX<D> {
403 pub(crate) fn new(target: D) -> Self {
404 MirrorX { target }
405 }
406
407 pub(crate) fn into_inner(self) -> D {
408 self.target
409 }
410 }
411
412 impl<D> AsRef<D> for MirrorX<D> {
413 fn as_ref(&self) -> &D {
414 &self.target
415 }
416 }
417
418 impl<D> AsMut<D> for MirrorX<D> {
419 fn as_mut(&mut self) -> &mut D {
420 &mut self.target
421 }
422 }
423
424 impl<D: Dimensions> Dimensions for MirrorX<D> {
425 #[inline]
426 fn bounding_box(&self) -> Rectangle {
427 self.target.bounding_box()
428 }
429 }
430
431 impl<D: DrawTarget> DrawTarget for MirrorX<D> {
432 type Color = D::Color;
433 type Error = D::Error;
434
435 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
436 where
437 I: IntoIterator<Item = Pixel<Self::Color>>,
438 {
439 let width = self.bounding_box().size.width as i32 - 1;
440
441 self.target.draw_iter(
442 pixels
443 .into_iter()
444 .map(|Pixel(Point { x, y }, col)| Pixel(Point { x: width - x, y }, col)),
445 )
446 }
447
448 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
449 let width = self.bounding_box().size.width as i32 - 1;
450 let area = Rectangle {
451 top_left: Point {
452 x: width - area.top_left.x - area.size.width as i32,
453 y: area.top_left.y,
454 },
455 size: area.size,
456 };
457 self.target.fill_solid(&area, color)
458 }
459
460 #[inline]
461 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
462 self.target.clear(color)
463 }
464 }
465
466 pub(crate) struct MirrorY<D> {
467 target: D,
468 }
469
470 impl<D> MirrorY<D> {
471 pub(crate) fn new(target: D) -> Self {
472 MirrorY { target }
473 }
474
475 pub(crate) fn into_inner(self) -> D {
476 self.target
477 }
478 }
479
480 impl<D> AsRef<D> for MirrorY<D> {
481 fn as_ref(&self) -> &D {
482 &self.target
483 }
484 }
485
486 impl<D> AsMut<D> for MirrorY<D> {
487 fn as_mut(&mut self) -> &mut D {
488 &mut self.target
489 }
490 }
491
492 impl<D: Dimensions> Dimensions for MirrorY<D> {
493 #[inline]
494 fn bounding_box(&self) -> Rectangle {
495 self.target.bounding_box()
496 }
497 }
498
499 impl<D: DrawTarget> DrawTarget for MirrorY<D> {
500 type Color = D::Color;
501 type Error = D::Error;
502
503 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
504 where
505 I: IntoIterator<Item = Pixel<Self::Color>>,
506 {
507 let height = self.bounding_box().size.height as i32 - 1;
508
509 self.target.draw_iter(
510 pixels
511 .into_iter()
512 .map(|Pixel(Point { x, y }, col)| Pixel(Point { x, y: height - y }, col)),
513 )
514 }
515
516 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
517 let height = self.bounding_box().size.height as i32 - 1;
518 let area = Rectangle {
519 top_left: Point {
520 x: area.top_left.x,
521 y: height - area.top_left.y - area.size.height as i32,
522 },
523 size: area.size,
524 };
525 self.target.fill_solid(&area, color)
526 }
527
528 #[inline]
529 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
530 self.target.clear(color)
531 }
532 }
533}