use embedded_graphics::{ image::{GetPixel, Image, ImageRaw}, iterator::raw::RawDataSlice, pixelcolor::{raw::LittleEndian, Bgr888, Rgb555, Rgb565, Rgb888}, prelude::*, }; use tinybmp::Bmp; const WIDTH: usize = 240; const HEIGHT: usize = 320; // TODO: use e-g framebuffer when it's added #[derive(Debug, PartialEq)] struct Framebuffer { pixels: [[C; 240]; 320], } impl + std::fmt::Debug> Framebuffer { pub fn new() -> Self { let color = C::from(Rgb888::BLACK); Self { pixels: [[color; WIDTH]; HEIGHT], } } pub fn from_image(image: impl ImageDrawable) -> Self { let mut framebuffer = Framebuffer::::new(); Image::new(&image, Point::zero()) .draw(&mut framebuffer) .unwrap(); framebuffer } pub fn pixels(&self) -> impl Iterator + '_ { self.pixels.iter().flatten().copied() } pub fn assert_eq(&self, expected: &Self) { let zipped = || self.pixels().zip(expected.pixels()); let errors = zipped().filter(|(a, b)| a != b).count(); let first_error = zipped() .enumerate() .find(|(_, (a, b))| a != b) .map(|(i, (a, b))| (Point::new((i % WIDTH) as i32, (i / WIDTH) as i32), a, b)); //let first_error = self.pixels() if self != expected { let first_error = first_error.unwrap(); panic!( "framebuffer differs from expected\n{} errors\nfirst error at ({}): {:?} (expected {:?})", errors, first_error.0, first_error.1, first_error.2, ); } } } impl DrawTarget for Framebuffer { type Color = C; type Error = std::convert::Infallible; fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> where I: IntoIterator>, { for Pixel(p, c) in pixels { self.pixels[p.y as usize][p.x as usize] = c; } Ok(()) } } impl OriginDimensions for Framebuffer { fn size(&self) -> embedded_graphics::prelude::Size { Size::new(240, 320) } } fn draw_raw(data: &[u8]) -> Framebuffer where C: PixelColor + From + From + std::fmt::Debug, for<'a> RawDataSlice<'a, C::Raw, LittleEndian>: IntoIterator, { let raw = ImageRaw::::new(data, 240); Framebuffer::from_image(raw) } fn draw_bmp(data: &[u8]) -> Framebuffer where C: PixelColor + From + From + From + std::fmt::Debug, { let bmp = Bmp::::from_slice(data).unwrap(); Framebuffer::from_image(bmp) } fn draw_bmp_pixel_getter(data: &[u8]) -> Framebuffer where C: PixelColor + From + From + From + std::fmt::Debug, { let bmp = Bmp::::from_slice(data).unwrap(); let mut fb = Framebuffer::new(); let bb = bmp.bounding_box(); assert_eq!(bb.top_left, Point::zero()); assert_eq!(bb.size, Size::new(240, 320)); assert_eq!(bb.points().count(), 320 * 240); bmp.bounding_box() .points() .map(|p| Pixel(p, bmp.pixel(p).unwrap())) .draw(&mut fb) .unwrap(); fb } #[test] fn logo_indexed_1bpp() { let raw = draw_raw::(include_bytes!("logo-indexed-1bpp.raw")); let bmp = draw_bmp::(include_bytes!("logo-indexed-1bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_indexed_1bpp_pixel_getter() { let raw = draw_raw::(include_bytes!("logo-indexed-1bpp.raw")); let bmp = draw_bmp_pixel_getter::(include_bytes!("logo-indexed-1bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_indexed_4bpp() { let raw = draw_raw::(include_bytes!("logo-indexed-4bpp.raw")); let bmp = draw_bmp::(include_bytes!("logo-indexed-4bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_indexed_4bpp_rle4() { let raw = draw_raw::(include_bytes!("logo-indexed-4bpp.raw")); let bmp = draw_bmp::(include_bytes!("logo-indexed-4bpp-rle4.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_indexed_4bpp_pixel_getter() { let raw = draw_raw::(include_bytes!("logo-indexed-4bpp.raw")); let bmp = draw_bmp_pixel_getter::(include_bytes!("logo-indexed-4bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_indexed_8bpp() { let raw = draw_raw::(include_bytes!("logo-indexed-8bpp.raw")); let bmp = draw_bmp::(include_bytes!("logo-indexed-8bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_indexed_8bpp_pixel_getter() { let raw = draw_raw::(include_bytes!("logo-indexed-8bpp.raw")); let bmp = draw_bmp_pixel_getter::(include_bytes!("logo-indexed-8bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_indexed_8bpp_rle8() { let raw = draw_raw::(include_bytes!("logo-indexed-8bpp.raw")); let bmp = draw_bmp::(include_bytes!("logo-indexed-8bpp-rle8.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_rgb555() { let raw = draw_raw::(include_bytes!("logo-rgb555.raw")); let bmp = draw_bmp::(include_bytes!("logo-rgb555.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_rgb555_pixel_getter() { let raw = draw_raw::(include_bytes!("logo-rgb555.raw")); let bmp = draw_bmp_pixel_getter::(include_bytes!("logo-rgb555.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_rgb565() { let raw = draw_raw::(include_bytes!("logo-rgb565.raw")); let bmp = draw_bmp::(include_bytes!("logo-rgb565.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_rgb565_pixel_getter() { let raw = draw_raw::(include_bytes!("logo-rgb565.raw")); let bmp = draw_bmp_pixel_getter::(include_bytes!("logo-rgb565.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_rgb888_24bpp() { let raw = draw_raw::(include_bytes!("logo-rgb888.raw")); let bmp = draw_bmp::(include_bytes!("logo-rgb888-24bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_rgb888_24bpp_pixel_getter() { let raw = draw_raw::(include_bytes!("logo-rgb888.raw")); let bmp = draw_bmp_pixel_getter::(include_bytes!("logo-rgb888-24bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_rgb888_32bpp() { let raw = draw_raw::(include_bytes!("logo-rgb888.raw")); let bmp = draw_bmp::(include_bytes!("logo-rgb888-32bpp.bmp")); bmp.assert_eq(&raw); } #[test] fn logo_rgb888_32bpp_pixel_getter() { let raw = draw_raw::(include_bytes!("logo-rgb888.raw")); let bmp = draw_bmp_pixel_getter::(include_bytes!("logo-rgb888-32bpp.bmp")); bmp.assert_eq(&raw); }