1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::{framebuffer::Framebuffer, output_settings::OutputSettings};
use embedded_graphics::{
drawable::Pixel,
geometry::{Point, Size},
pixelcolor::{BinaryColor, PixelColor, Rgb888},
DrawTarget,
};
use image::{ImageBuffer, Rgb};
use std::convert::TryFrom;
/// Simulator display.
pub struct SimulatorDisplay<C> {
size: Size,
pixels: Box<[C]>,
}
impl<C> SimulatorDisplay<C>
where
C: PixelColor,
{
/// Creates a new display filled with a color.
///
/// This constructor can be used if `C` doesn't implement `From<BinaryColor>` or another
/// default color is wanted.
pub fn with_default_color(size: Size, default_color: C) -> Self {
let pixel_count = size.width as usize * size.height as usize;
let pixels = vec![default_color; pixel_count].into_boxed_slice();
SimulatorDisplay { size, pixels }
}
/// Returns the color of the pixel at a point.
///
/// # Panics
///
/// Panics if `point` is outside the display.
pub fn get_pixel(&self, point: Point) -> C {
self.point_to_index(point)
.and_then(|index| self.pixels.get(index).copied())
.expect("can't get point outside of display")
}
fn point_to_index(&self, point: Point) -> Option<usize> {
if let Ok((x, y)) = <(u32, u32)>::try_from(point) {
if x < self.size.width && y < self.size.height {
return Some((x + y * self.size.width) as usize);
}
}
None
}
}
impl<C> SimulatorDisplay<C>
where
C: PixelColor + From<BinaryColor>,
{
/// Creates a new display.
///
/// The display is filled with `C::from(BinaryColor::Off)`.
pub fn new(size: Size) -> Self {
Self::with_default_color(size, C::from(BinaryColor::Off))
}
}
impl<C> SimulatorDisplay<C>
where
C: PixelColor + Into<Rgb888>,
{
/// Converts the display contents into an image.rs `ImageBuffer`.
///
/// # Examples
///
/// ```rust
/// use embedded_graphics::{prelude::*, pixelcolor::Rgb888};
/// use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay};
///
/// let output_settings = OutputSettingsBuilder::new().scale(2).build();
///
/// let display: SimulatorDisplay<Rgb888> = SimulatorDisplay::new(Size::new(128, 64));
///
/// // draw something to the display
///
/// let image_buffer = display.to_image_buffer(&output_settings);
/// assert_eq!(image_buffer.width(), 256);
/// assert_eq!(image_buffer.height(), 128);
///
/// // use image buffer
/// // example: image_buffer.save
/// ```
pub fn to_image_buffer(
&self,
output_settings: &OutputSettings,
) -> ImageBuffer<Rgb<u8>, Box<[u8]>> {
let framebuffer = Framebuffer::new(self, output_settings);
framebuffer.into_image_buffer()
}
}
impl<C> DrawTarget<C> for SimulatorDisplay<C>
where
C: PixelColor,
{
type Error = core::convert::Infallible;
fn draw_pixel(&mut self, pixel: Pixel<C>) -> Result<(), Self::Error> {
let Pixel(point, color) = pixel;
if let Some(index) = self.point_to_index(point) {
self.pixels[index] = color;
}
Ok(())
}
fn size(&self) -> Size {
self.size
}
}