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, //