1use std::{convert::TryFrom, fs::File, io::BufReader, path::Path};
2
3use embedded_graphics::{
4 pixelcolor::{raw::ToBytes, BinaryColor, Gray8, Rgb888},
5 prelude::*,
6};
7
8use crate::{output_image::OutputImage, output_settings::OutputSettings};
9
10#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct SimulatorDisplay<C> {
13 size: Size,
14 pub(crate) pixels: Box<[C]>,
15}
16
17impl<C: PixelColor> SimulatorDisplay<C> {
18 pub fn with_default_color(size: Size, default_color: C) -> Self {
23 let pixel_count = size.width as usize * size.height as usize;
24 let pixels = vec![default_color; pixel_count].into_boxed_slice();
25
26 SimulatorDisplay { size, pixels }
27 }
28
29 pub fn get_pixel(&self, point: Point) -> C {
35 self.point_to_index(point)
36 .and_then(|index| self.pixels.get(index).copied())
37 .expect("can't get point outside of display")
38 }
39
40 fn point_to_index(&self, point: Point) -> Option<usize> {
41 if let Ok((x, y)) = <(u32, u32)>::try_from(point) {
42 if x < self.size.width && y < self.size.height {
43 return Some((x + y * self.size.width) as usize);
44 }
45 }
46
47 None
48 }
49
50 pub fn diff(&self, other: &SimulatorDisplay<C>) -> Option<SimulatorDisplay<BinaryColor>> {
60 assert!(
61 self.size == other.size,
62 "both displays must have the same size (self: {}x{}, other: {}x{})",
64 self.size.width,
65 self.size.height,
66 other.size.width,
67 other.size.height,
68 );
69
70 let pixels = self
71 .bounding_box()
72 .points()
73 .map(|p| BinaryColor::from(self.get_pixel(p) != other.get_pixel(p)))
74 .collect::<Vec<_>>()
75 .into_boxed_slice();
76
77 if pixels.iter().any(|p| *p == BinaryColor::On) {
78 Some(SimulatorDisplay {
79 pixels,
80 size: self.size,
81 })
82 } else {
83 None
84 }
85 }
86}
87
88impl<C> SimulatorDisplay<C>
89where
90 C: PixelColor + From<BinaryColor>,
91{
92 pub fn new(size: Size) -> Self {
96 Self::with_default_color(size, C::from(BinaryColor::Off))
97 }
98}
99
100impl<C> SimulatorDisplay<C>
101where
102 C: PixelColor + Into<Rgb888>,
103{
104 pub fn to_rgb_output_image(&self, output_settings: &OutputSettings) -> OutputImage<Rgb888> {
125 let mut output = OutputImage::new(self, output_settings);
126 output.update(self);
127
128 output
129 }
130
131 pub fn to_grayscale_output_image(
152 &self,
153 output_settings: &OutputSettings,
154 ) -> OutputImage<Gray8> {
155 let mut output = OutputImage::new(self, output_settings);
156 output.update(self);
157
158 output
159 }
160}
161
162impl<C> SimulatorDisplay<C>
163where
164 C: PixelColor + ToBytes,
165 <C as ToBytes>::Bytes: AsRef<[u8]>,
166{
167 pub fn to_be_bytes(&self) -> Vec<u8> {
169 self.to_bytes(ToBytes::to_be_bytes)
170 }
171
172 pub fn to_le_bytes(&self) -> Vec<u8> {
174 self.to_bytes(ToBytes::to_le_bytes)
175 }
176
177 pub fn to_ne_bytes(&self) -> Vec<u8> {
179 self.to_bytes(ToBytes::to_ne_bytes)
180 }
181
182 fn to_bytes<F>(&self, pixel_to_bytes: F) -> Vec<u8>
183 where
184 F: Fn(C) -> C::Bytes,
185 {
186 let mut bytes = Vec::new();
187
188 if C::Raw::BITS_PER_PIXEL >= 8 {
189 for pixel in self.pixels.iter() {
190 bytes.extend_from_slice(pixel_to_bytes(*pixel).as_ref())
191 }
192 } else {
193 let pixels_per_byte = 8 / C::Raw::BITS_PER_PIXEL;
194
195 for row in self.pixels.chunks(self.size.width as usize) {
196 for byte_pixels in row.chunks(pixels_per_byte) {
197 let mut value = 0;
198
199 for pixel in byte_pixels {
200 value <<= C::Raw::BITS_PER_PIXEL;
201 value |= pixel.to_be_bytes().as_ref()[0];
202 }
203
204 value <<= C::Raw::BITS_PER_PIXEL * (pixels_per_byte - byte_pixels.len());
205
206 bytes.push(value);
207 }
208 }
209 }
210
211 bytes
212 }
213}
214
215impl<C> SimulatorDisplay<C>
216where
217 C: PixelColor + From<Rgb888>,
218{
219 pub fn load_png<P: AsRef<Path>>(path: P) -> image::ImageResult<Self> {
221 let png_file = BufReader::new(File::open(path)?);
222 let image = image::load(png_file, image::ImageFormat::Png)?.to_rgb8();
223
224 let pixels = image
225 .pixels()
226 .map(|p| Rgb888::new(p[0], p[1], p[2]).into())
227 .collect();
228
229 Ok(Self {
230 size: Size::new(image.width(), image.height()),
231 pixels,
232 })
233 }
234}
235
236impl<C: PixelColor> DrawTarget for SimulatorDisplay<C> {
237 type Color = C;
238 type Error = core::convert::Infallible;
239
240 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
241 where
242 I: IntoIterator<Item = Pixel<Self::Color>>,
243 {
244 for Pixel(point, color) in pixels.into_iter() {
245 if let Some(index) = self.point_to_index(point) {
246 self.pixels[index] = color;
247 }
248 }
249
250 Ok(())
251 }
252}
253
254impl<C> OriginDimensions for SimulatorDisplay<C> {
255 fn size(&self) -> Size {
256 self.size
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 use embedded_graphics::{
265 pixelcolor::{Gray2, Gray4, Rgb565},
266 primitives::{Circle, Line, PrimitiveStyle},
267 };
268
269 #[test]
270 fn rgb_output_image() {
271 let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(2, 4));
272
273 Line::new(Point::new(0, 0), Point::new(1, 3))
274 .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
275 .draw(&mut display)
276 .unwrap();
277
278 let image = display.to_rgb_output_image(&OutputSettings::default());
279 assert_eq!(image.size(), display.size());
280
281 let expected: &[u8] = &[
282 255, 255, 255, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 255, 255, 255, ];
287 assert_eq!(image.data.as_ref(), expected);
288 }
289
290 #[test]
291 fn grayscale_image_buffer() {
292 let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(2, 4));
293
294 Line::new(Point::new(0, 0), Point::new(1, 3))
295 .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
296 .draw(&mut display)
297 .unwrap();
298
299 let image = display.to_grayscale_output_image(&OutputSettings::default());
300 assert_eq!(image.size(), display.size());
301
302 let expected: &[u8] = &[
303 255, 0, 255, 0, 0, 255, 0, 255, ];
308 assert_eq!(image.data.as_ref(), expected);
309 }
310
311 #[test]
312 fn to_bytes_u1() {
313 let display = SimulatorDisplay {
314 size: Size::new(9, 3),
315 pixels: [
316 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, ]
320 .iter()
321 .map(|c| BinaryColor::from(*c != 0))
322 .collect::<Vec<_>>()
323 .into_boxed_slice(),
324 };
325
326 let expected = [
327 0b10000001, 0b00000000, 0b01000010, 0b10000000, 0b00100100, 0b00000000, ];
331 assert_eq!(&display.to_be_bytes(), &expected);
332 assert_eq!(&display.to_le_bytes(), &expected);
333 assert_eq!(&display.to_ne_bytes(), &expected);
334 }
335
336 #[test]
337 fn to_bytes_u2() {
338 let display = SimulatorDisplay {
339 size: Size::new(5, 2),
340 pixels: [
341 0, 1, 2, 3, 0, 1, 0, 3, 2, 1, ]
344 .iter()
345 .map(|c| Gray2::new(*c))
346 .collect::<Vec<_>>()
347 .into_boxed_slice(),
348 };
349
350 let expected = [
351 0b00011011, 0b00000000, 0b01001110, 0b01000000, ];
354 assert_eq!(&display.to_be_bytes(), &expected);
355 assert_eq!(&display.to_le_bytes(), &expected);
356 assert_eq!(&display.to_ne_bytes(), &expected);
357 }
358
359 #[test]
360 fn to_bytes_u4() {
361 let display = SimulatorDisplay {
362 size: Size::new(5, 4),
363 pixels: [
364 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x0, 0x0, 0x0, ]
369 .iter()
370 .map(|c| Gray4::new(*c))
371 .collect::<Vec<_>>()
372 .into_boxed_slice(),
373 };
374
375 let expected = [
376 0x01, 0x23, 0x40, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xE0, 0xF0, 0x00, 0x00, ];
381 assert_eq!(&display.to_be_bytes(), &expected);
382 assert_eq!(&display.to_le_bytes(), &expected);
383 assert_eq!(&display.to_ne_bytes(), &expected);
384 }
385
386 #[test]
387 fn to_bytes_u8() {
388 let expected = [
389 1, 2, 3, 11, 12, 13, ];
392
393 let display = SimulatorDisplay {
394 size: Size::new(3, 2),
395 pixels: expected
396 .iter()
397 .copied()
398 .map(Gray8::new)
399 .collect::<Vec<_>>()
400 .into_boxed_slice(),
401 };
402
403 assert_eq!(&display.to_be_bytes(), &expected);
404 assert_eq!(&display.to_le_bytes(), &expected);
405 assert_eq!(&display.to_ne_bytes(), &expected);
406 }
407
408 #[test]
409 fn to_bytes_u16() {
410 let expected = vec![Rgb565::new(0x10, 0x00, 0x00), Rgb565::new(0x00, 0x00, 0x01)];
411
412 let display = SimulatorDisplay {
413 size: Size::new(2, 1),
414 pixels: expected.clone().into_boxed_slice(),
415 };
416
417 assert_eq!(&display.to_be_bytes(), &[0x80, 0x00, 0x00, 0x01]);
418 assert_eq!(&display.to_le_bytes(), &[0x00, 0x80, 0x01, 0x00]);
419 }
420
421 #[test]
422 fn to_bytes_u24() {
423 let expected = vec![Rgb888::new(0x80, 0x00, 0x00), Rgb888::new(0x00, 0x00, 0x01)];
424
425 let display = SimulatorDisplay {
426 size: Size::new(2, 1),
427 pixels: expected.clone().into_boxed_slice(),
428 };
429
430 assert_eq!(
431 &display.to_be_bytes(),
432 &[0x80, 0x00, 0x00, 0x00, 0x00, 0x01]
433 );
434 assert_eq!(
435 &display.to_le_bytes(),
436 &[0x00, 0x00, 0x80, 0x01, 0x00, 0x00]
437 );
438 }
439
440 #[test]
441 fn diff_equal() {
442 let display = SimulatorDisplay::<BinaryColor>::new(Size::new(4, 6));
443 let expected = display.clone();
444
445 assert_eq!(display.diff(&expected), None);
446 }
447
448 #[test]
449 fn diff_not_equal() {
450 let circle = Circle::new(Point::zero(), 3);
451
452 let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(4, 6));
453 let expected = display.clone();
454
455 circle
456 .into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
457 .draw(&mut display)
458 .unwrap();
459
460 assert_eq!(display.diff(&expected), Some(display));
461 }
462
463 #[test]
464 #[should_panic(expected = "both displays must have the same size (self: 4x6, other: 4x5)")]
465 fn diff_wrong_size() {
466 let display = SimulatorDisplay::<BinaryColor>::new(Size::new(4, 6));
467 let expected = SimulatorDisplay::<BinaryColor>::new(Size::new(4, 5));
468
469 assert_eq!(display.diff(&expected), None);
470 }
471}