1use std::{
2 convert::TryFrom,
3 fs::File,
4 io::BufReader,
5 path::Path,
6 sync::atomic::{AtomicUsize, Ordering},
7};
8
9use embedded_graphics::{
10 pixelcolor::{raw::ToBytes, BinaryColor, Gray8, Rgb888},
11 prelude::*,
12};
13
14use crate::{output_image::OutputImage, output_settings::OutputSettings};
15
16static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
17
18#[derive(Debug, Clone, Eq, PartialOrd, Ord, Hash)]
20pub struct SimulatorDisplay<C> {
21 size: Size,
22 pub(crate) pixels: Box<[C]>,
23 pub(crate) id: usize,
24}
25
26impl<C: PixelColor> SimulatorDisplay<C> {
27 fn new_common(size: Size, pixels: Box<[C]>) -> Self {
28 let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
29
30 Self { size, pixels, id }
31 }
32
33 pub fn with_default_color(size: Size, default_color: C) -> Self {
38 let pixel_count = size.width as usize * size.height as usize;
39 let pixels = vec![default_color; pixel_count].into_boxed_slice();
40
41 SimulatorDisplay::new_common(size, pixels)
42 }
43
44 pub fn get_pixel(&self, point: Point) -> C {
50 self.point_to_index(point)
51 .and_then(|index| self.pixels.get(index).copied())
52 .expect("can't get point outside of display")
53 }
54
55 fn point_to_index(&self, point: Point) -> Option<usize> {
56 if let Ok((x, y)) = <(u32, u32)>::try_from(point) {
57 if x < self.size.width && y < self.size.height {
58 return Some((x + y * self.size.width) as usize);
59 }
60 }
61
62 None
63 }
64
65 pub fn diff(&self, other: &SimulatorDisplay<C>) -> Option<SimulatorDisplay<BinaryColor>> {
75 assert!(
76 self.size == other.size,
77 "both displays must have the same size (self: {}x{}, other: {}x{})",
79 self.size.width,
80 self.size.height,
81 other.size.width,
82 other.size.height,
83 );
84
85 let pixels = self
86 .bounding_box()
87 .points()
88 .map(|p| BinaryColor::from(self.get_pixel(p) != other.get_pixel(p)))
89 .collect::<Vec<_>>()
90 .into_boxed_slice();
91
92 if pixels.iter().any(|p| *p == BinaryColor::On) {
93 Some(SimulatorDisplay::new_common(self.size, pixels))
94 } else {
95 None
96 }
97 }
98
99 pub fn output_size(&self, output_settings: &OutputSettings) -> Size {
105 self.size * output_settings.scale
106 + self.size.saturating_sub(Size::new_equal(1)) * output_settings.pixel_spacing
107 }
108}
109
110impl<C> SimulatorDisplay<C>
111where
112 C: PixelColor + From<BinaryColor>,
113{
114 pub fn new(size: Size) -> Self {
118 Self::with_default_color(size, C::from(BinaryColor::Off))
119 }
120}
121
122impl<C> SimulatorDisplay<C>
123where
124 C: PixelColor + Into<Rgb888>,
125{
126 pub fn to_rgb_output_image(&self, output_settings: &OutputSettings) -> OutputImage<Rgb888> {
147 let mut output = OutputImage::new(self.output_size(output_settings));
148 output.draw_display(self, Point::zero(), output_settings);
149
150 output
151 }
152
153 pub fn to_grayscale_output_image(
174 &self,
175 output_settings: &OutputSettings,
176 ) -> OutputImage<Gray8> {
177 let size = self.output_size(output_settings);
178 let mut output = OutputImage::new(size);
179 output.draw_display(self, Point::zero(), output_settings);
180
181 output
182 }
183}
184
185impl<C> SimulatorDisplay<C>
186where
187 C: PixelColor + ToBytes,
188 <C as ToBytes>::Bytes: AsRef<[u8]>,
189{
190 pub fn to_be_bytes(&self) -> Vec<u8> {
192 self.to_bytes(ToBytes::to_be_bytes)
193 }
194
195 pub fn to_le_bytes(&self) -> Vec<u8> {
197 self.to_bytes(ToBytes::to_le_bytes)
198 }
199
200 pub fn to_ne_bytes(&self) -> Vec<u8> {
202 self.to_bytes(ToBytes::to_ne_bytes)
203 }
204
205 fn to_bytes<F>(&self, pixel_to_bytes: F) -> Vec<u8>
206 where
207 F: Fn(C) -> C::Bytes,
208 {
209 let mut bytes = Vec::new();
210
211 if C::Raw::BITS_PER_PIXEL >= 8 {
212 for pixel in self.pixels.iter() {
213 bytes.extend_from_slice(pixel_to_bytes(*pixel).as_ref())
214 }
215 } else {
216 let pixels_per_byte = 8 / C::Raw::BITS_PER_PIXEL;
217
218 for row in self.pixels.chunks(self.size.width as usize) {
219 for byte_pixels in row.chunks(pixels_per_byte) {
220 let mut value = 0;
221
222 for pixel in byte_pixels {
223 value <<= C::Raw::BITS_PER_PIXEL;
224 value |= pixel.to_be_bytes().as_ref()[0];
225 }
226
227 value <<= C::Raw::BITS_PER_PIXEL * (pixels_per_byte - byte_pixels.len());
228
229 bytes.push(value);
230 }
231 }
232 }
233
234 bytes
235 }
236}
237
238impl<C> SimulatorDisplay<C>
239where
240 C: PixelColor + From<Rgb888>,
241{
242 pub fn load_png<P: AsRef<Path>>(path: P) -> image::ImageResult<Self> {
244 let png_file = BufReader::new(File::open(path)?);
245 let image = image::load(png_file, image::ImageFormat::Png)?.to_rgb8();
246
247 let pixels = image
248 .pixels()
249 .map(|p| Rgb888::new(p[0], p[1], p[2]).into())
250 .collect();
251
252 Ok(Self::new_common(
253 Size::new(image.width(), image.height()),
254 pixels,
255 ))
256 }
257}
258
259impl<C: PixelColor> DrawTarget for SimulatorDisplay<C> {
260 type Color = C;
261 type Error = core::convert::Infallible;
262
263 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
264 where
265 I: IntoIterator<Item = Pixel<Self::Color>>,
266 {
267 for Pixel(point, color) in pixels.into_iter() {
268 if let Some(index) = self.point_to_index(point) {
269 self.pixels[index] = color;
270 }
271 }
272
273 Ok(())
274 }
275}
276
277impl<C> OriginDimensions for SimulatorDisplay<C> {
278 fn size(&self) -> Size {
279 self.size
280 }
281}
282
283impl<C: PartialEq> PartialEq for SimulatorDisplay<C> {
284 fn eq(&self, other: &Self) -> bool {
285 self.size == other.size && self.pixels == other.pixels
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 use embedded_graphics::{
294 pixelcolor::{Gray2, Gray4, Rgb565},
295 primitives::{Circle, Line, PrimitiveStyle},
296 };
297
298 #[test]
299 fn rgb_output_image() {
300 let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(2, 4));
301
302 Line::new(Point::new(0, 0), Point::new(1, 3))
303 .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
304 .draw(&mut display)
305 .unwrap();
306
307 let image = display.to_rgb_output_image(&OutputSettings::default());
308 assert_eq!(image.size(), display.size());
309
310 let expected: &[u8] = &[
311 255, 255, 255, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 0, 255, 255, 255, ];
316 assert_eq!(image.data.as_ref(), expected);
317 }
318
319 #[test]
320 fn grayscale_image_buffer() {
321 let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(2, 4));
322
323 Line::new(Point::new(0, 0), Point::new(1, 3))
324 .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
325 .draw(&mut display)
326 .unwrap();
327
328 let image = display.to_grayscale_output_image(&OutputSettings::default());
329 assert_eq!(image.size(), display.size());
330
331 let expected: &[u8] = &[
332 255, 0, 255, 0, 0, 255, 0, 255, ];
337 assert_eq!(image.data.as_ref(), expected);
338 }
339
340 #[test]
341 fn to_bytes_u1() {
342 let display = SimulatorDisplay {
343 size: Size::new(9, 3),
344 pixels: [
345 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, ]
349 .iter()
350 .map(|c| BinaryColor::from(*c != 0))
351 .collect::<Vec<_>>()
352 .into_boxed_slice(),
353 id: 0,
354 };
355
356 let expected = [
357 0b10000001, 0b00000000, 0b01000010, 0b10000000, 0b00100100, 0b00000000, ];
361 assert_eq!(&display.to_be_bytes(), &expected);
362 assert_eq!(&display.to_le_bytes(), &expected);
363 assert_eq!(&display.to_ne_bytes(), &expected);
364 }
365
366 #[test]
367 fn to_bytes_u2() {
368 let display = SimulatorDisplay {
369 size: Size::new(5, 2),
370 pixels: [
371 0, 1, 2, 3, 0, 1, 0, 3, 2, 1, ]
374 .iter()
375 .map(|c| Gray2::new(*c))
376 .collect::<Vec<_>>()
377 .into_boxed_slice(),
378 id: 0,
379 };
380
381 let expected = [
382 0b00011011, 0b00000000, 0b01001110, 0b01000000, ];
385 assert_eq!(&display.to_be_bytes(), &expected);
386 assert_eq!(&display.to_le_bytes(), &expected);
387 assert_eq!(&display.to_ne_bytes(), &expected);
388 }
389
390 #[test]
391 fn to_bytes_u4() {
392 let display = SimulatorDisplay {
393 size: Size::new(5, 4),
394 pixels: [
395 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x0, 0x0, 0x0, ]
400 .iter()
401 .map(|c| Gray4::new(*c))
402 .collect::<Vec<_>>()
403 .into_boxed_slice(),
404 id: 0,
405 };
406
407 let expected = [
408 0x01, 0x23, 0x40, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xE0, 0xF0, 0x00, 0x00, ];
413 assert_eq!(&display.to_be_bytes(), &expected);
414 assert_eq!(&display.to_le_bytes(), &expected);
415 assert_eq!(&display.to_ne_bytes(), &expected);
416 }
417
418 #[test]
419 fn to_bytes_u8() {
420 let expected = [
421 1, 2, 3, 11, 12, 13, ];
424
425 let display = SimulatorDisplay {
426 size: Size::new(3, 2),
427 pixels: expected
428 .iter()
429 .copied()
430 .map(Gray8::new)
431 .collect::<Vec<_>>()
432 .into_boxed_slice(),
433 id: 0,
434 };
435
436 assert_eq!(&display.to_be_bytes(), &expected);
437 assert_eq!(&display.to_le_bytes(), &expected);
438 assert_eq!(&display.to_ne_bytes(), &expected);
439 }
440
441 #[test]
442 fn to_bytes_u16() {
443 let expected = vec![Rgb565::new(0x10, 0x00, 0x00), Rgb565::new(0x00, 0x00, 0x01)];
444
445 let display = SimulatorDisplay {
446 size: Size::new(2, 1),
447 pixels: expected.clone().into_boxed_slice(),
448 id: 0,
449 };
450
451 assert_eq!(&display.to_be_bytes(), &[0x80, 0x00, 0x00, 0x01]);
452 assert_eq!(&display.to_le_bytes(), &[0x00, 0x80, 0x01, 0x00]);
453 }
454
455 #[test]
456 fn to_bytes_u24() {
457 let expected = vec![Rgb888::new(0x80, 0x00, 0x00), Rgb888::new(0x00, 0x00, 0x01)];
458
459 let display = SimulatorDisplay {
460 size: Size::new(2, 1),
461 pixels: expected.clone().into_boxed_slice(),
462 id: 0,
463 };
464
465 assert_eq!(
466 &display.to_be_bytes(),
467 &[0x80, 0x00, 0x00, 0x00, 0x00, 0x01]
468 );
469 assert_eq!(
470 &display.to_le_bytes(),
471 &[0x00, 0x00, 0x80, 0x01, 0x00, 0x00]
472 );
473 }
474
475 #[test]
476 fn diff_equal() {
477 let display = SimulatorDisplay::<BinaryColor>::new(Size::new(4, 6));
478 let expected = display.clone();
479
480 assert_eq!(display.diff(&expected), None);
481 }
482
483 #[test]
484 fn diff_not_equal() {
485 let circle = Circle::new(Point::zero(), 3);
486
487 let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(4, 6));
488 let expected = display.clone();
489
490 circle
491 .into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
492 .draw(&mut display)
493 .unwrap();
494
495 assert_eq!(display.diff(&expected), Some(display));
496 }
497
498 #[test]
499 #[should_panic(expected = "both displays must have the same size (self: 4x6, other: 4x5)")]
500 fn diff_wrong_size() {
501 let display = SimulatorDisplay::<BinaryColor>::new(Size::new(4, 6));
502 let expected = SimulatorDisplay::<BinaryColor>::new(Size::new(4, 5));
503
504 assert_eq!(display.diff(&expected), None);
505 }
506}