diff --git a/mipidsi/docs/test_image.svg b/mipidsi/docs/test_image.svg new file mode 100644 index 0000000..ad588b5 --- /dev/null +++ b/mipidsi/docs/test_image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/mipidsi/src/test_image.rs b/mipidsi/src/test_image.rs index 66e2675..a2c6399 100644 --- a/mipidsi/src/test_image.rs +++ b/mipidsi/src/test_image.rs @@ -10,6 +10,29 @@ use embedded_graphics_core::{ /// /// The test image can be used to check if the display is working and to /// identify the correct orientation and color settings. +/// +/// # Expected output +/// +#[doc = include_str!("../docs/test_image.svg")] +/// +/// Note that the gray border around the image above is only added to make the +/// white border visible on the light rustdoc theme and will not be visible when +/// the test image is drawn. +/// +/// - There should be a one pixel white border around the display. +/// Modify the [display size](crate::Builder::with_display_size) and [display +/// offset](crate::Builder::with_display_offset) settings, if at least one +/// edge of the white border isn't drawn or if there is a gap between the +/// white border and the edge of the display. +/// - A white triangle should be drawn in the top left corner and the RGB label text should not be mirrored. +/// Modify the [orientation](crate::Builder::with_orientation) setting to +/// rotate and mirror the display until the test image is displayed correctly. +/// Note that the white triangle might not be visible on displays with rounded +/// corners. +/// - The colored bars should match the labels. +/// Use the [color inversion](crate::Builder::with_invert_colors) and [color +/// order](crate::Builder::with_color_order) settings until the colored bars +/// and labels match. #[derive(Default)] pub struct TestImage { color_type: PhantomData, @@ -24,8 +47,9 @@ impl TestImage { } } -const CORNER_SIZE: u32 = 10; -const CORNER_STROKE_WIDTH: u32 = 1; +const BORDER_WIDTH: u32 = 1; +const BORDER_PADDING: u32 = 4; +const TOP_LEFT_MARKER_SIZE: u32 = 20; impl Drawable for TestImage { type Color = C; @@ -35,44 +59,78 @@ impl Drawable for TestImage { where D: DrawTarget, { - let bounding_box = target.bounding_box(); - target.fill_solid(&bounding_box, RgbColor::GREEN)?; - Character::new(G, bounding_box.center()).draw(target)?; - - let rect = bounding_box.resized_width(bounding_box.size.width / 3, AnchorX::Left); - target.fill_solid(&rect, RgbColor::RED)?; - Character::new(R, rect.center()).draw(target)?; - - let rect = bounding_box.resized_width(bounding_box.size.width / 3, AnchorX::Right); - target.fill_solid(&rect, RgbColor::BLUE)?; - Character::new(B, rect.center()).draw(target)?; - - for anchor in [ - AnchorPoint::TopLeft, - AnchorPoint::TopRight, - AnchorPoint::BottomLeft, - AnchorPoint::BottomRight, - ] { - target.fill_solid( - &bounding_box.resized(Size::new(CORNER_SIZE, CORNER_STROKE_WIDTH), anchor), - C::WHITE, - )?; - target.fill_solid( - &bounding_box.resized(Size::new(CORNER_STROKE_WIDTH, CORNER_SIZE), anchor), - C::WHITE, - )?; - } + draw_border(target, BORDER_WIDTH)?; - let top_left_marker = Rectangle::new( - Point::new_equal((CORNER_STROKE_WIDTH * 3) as i32), - Size::new_equal(CORNER_SIZE - 3 * CORNER_STROKE_WIDTH), - ); - target.fill_solid(&top_left_marker, C::WHITE)?; + let color_bar_area = target + .bounding_box() + .offset(-i32::try_from(BORDER_WIDTH + BORDER_PADDING).unwrap()); + draw_color_bars(target, &color_bar_area)?; + + draw_top_left_marker(target, &color_bar_area, TOP_LEFT_MARKER_SIZE)?; Ok(()) } } +/// Draws a white border around the draw target. +fn draw_border(target: &mut D, width: u32) -> Result<(), D::Error> +where + D: DrawTarget, + D::Color: RgbColor, +{ + let bounding_box = target.bounding_box(); + let inner_box = bounding_box.offset(-i32::try_from(width).unwrap()); + + target.fill_contiguous( + &bounding_box, + bounding_box.points().map(|p| { + if inner_box.contains(p) { + D::Color::BLACK + } else { + D::Color::WHITE + } + }), + ) +} + +/// Draws RGB color bars and labels. +fn draw_color_bars(target: &mut D, area: &Rectangle) -> Result<(), D::Error> +where + D: DrawTarget, + D::Color: RgbColor, +{ + target.fill_solid(area, RgbColor::GREEN)?; + Character::new(G, area.center()).draw(target)?; + + let rect = area.resized_width(area.size.width / 3, AnchorX::Left); + target.fill_solid(&rect, RgbColor::RED)?; + Character::new(R, rect.center()).draw(target)?; + + let rect = area.resized_width(area.size.width / 3, AnchorX::Right); + target.fill_solid(&rect, RgbColor::BLUE)?; + Character::new(B, rect.center()).draw(target)?; + + Ok(()) +} + +// Draws a triangular marker in the top left corner. +fn draw_top_left_marker(target: &mut D, area: &Rectangle, size: u32) -> Result<(), D::Error> +where + D: DrawTarget, + D::Color: RgbColor, +{ + let mut rect = area.resized(Size::new(size, 1), AnchorPoint::TopLeft); + + while rect.size.width > 0 { + target.fill_solid(&rect, D::Color::WHITE)?; + + rect.top_left.y += 1; + rect.size.width -= 1; + } + + Ok(()) +} + const R: &[u8] = &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, 0, 0, 0, 0, //