embedded_graphics

Trait DrawTarget

Source
pub trait DrawTarget<C>
where C: PixelColor,
{ type Error; // Required methods fn draw_pixel(&mut self, item: Pixel<C>) -> Result<(), Self::Error>; fn size(&self) -> Size; // Provided methods fn draw_iter<T>(&mut self, item: T) -> Result<(), Self::Error> where T: IntoIterator<Item = Pixel<C>> { ... } fn clear(&mut self, color: C) -> Result<(), Self::Error> where Self: Sized { ... } fn draw_line( &mut self, item: &Styled<Line, PrimitiveStyle<C>>, ) -> Result<(), Self::Error> { ... } fn draw_triangle( &mut self, item: &Styled<Triangle, PrimitiveStyle<C>>, ) -> Result<(), Self::Error> { ... } fn draw_rectangle( &mut self, item: &Styled<Rectangle, PrimitiveStyle<C>>, ) -> Result<(), Self::Error> { ... } fn draw_circle( &mut self, item: &Styled<Circle, PrimitiveStyle<C>>, ) -> Result<(), Self::Error> { ... } fn draw_image<'a, 'b, I>( &mut self, item: &'a Image<'b, I, C>, ) -> Result<(), Self::Error> where &'b I: IntoPixelIter<C>, I: ImageDimensions, C: PixelColor + From<<C as PixelColor>::Raw> { ... } }
Expand description

Defines a display that can be used to render Drawable objects.

To to add embedded-graphics support to a display driver, DrawTarget must be implemented. Once a DrawTarget is defined, it can be used to render Drawables. Note that any iterator over Pixels can be drawn as Drawable is implemented for Iterator<Item = Pixel<C: PixelColor>>. See the Drawable trait documentation for more details.

DrawTarget provides default implementations of methods to draw primitives and clear the display which delegate to DrawTarget::draw_iter. If the target display supports accelerated drawing commands, these methods can be overridden with specialised implementations that take advantage of the hardware to speed up drawing operations.

Note that some displays require a “flush” operation to write changes from a framebuffer to the display. See docs associated with the chosen display driver for details on how to update the display.

§Examples

§Implement DrawTarget for an 8 bit grayscale display

This example uses an imaginary display that has a 64x64px framebuffer of 8 bit values that is sent to the display over a (simplified) SPI interface.

use core::convert::TryInto;
use embedded_graphics::{
    drawable::Pixel,
    egcircle,
    geometry::Size,
    pixelcolor::{Gray8, GrayColor},
    prelude::*,
    primitive_style, DrawTarget,
};

/// A fake 64px x 64px display where each pixel is stored as a single `u8`
struct ExampleDisplay {
    framebuffer: [u8; 64 * 64],
    iface: SPI1,
}

impl ExampleDisplay {
    /// Send buffer to the display
    pub fn flush(&self) -> Result<(), ()> {
        self.iface.send_bytes(&self.framebuffer)
    }
}

impl DrawTarget<Gray8> for ExampleDisplay {
    type Error = core::convert::Infallible;

    /// Draw a `Pixel` that has a color defined as `Gray8`.
    fn draw_pixel(&mut self, pixel: Pixel<Gray8>) -> Result<(), Self::Error> {
        let Pixel(coord, color) = pixel;

        // Place an (x, y) pixel at the right index in the framebuffer. If the pixel coordinates
        // are out of bounds (negative or greater than (63, 63)), this operation will be a
        // noop.
        if let Ok((x @ 0..=63, y @ 0..=63)) = coord.try_into() {
            let index: u32 = x + y * 64;
            self.framebuffer[index as usize] = color.luma();
        }

        Ok(())
    }

    fn size(&self) -> Size {
        Size::new(64, 64)
    }
}

let mut display = ExampleDisplay {
    framebuffer: [0; 4096],
    iface: SPI1,
};

// Draw a circle centered around `(32, 32)` with a radius of `10` and a white stroke
let circle = egcircle!(
    center = (32, 32),
    radius = 10,
    style = primitive_style!(stroke_color = Gray8::WHITE, stroke_width = 1)
);
circle.draw(&mut display)?;

// Update the display
display.flush().expect("Failed to send data to display");

§Hardware Acceleration

In addition to defining draw_pixel, an implementation of DrawTarget can also provide alternative implementations for hardware accelerated drawing operations. This example implements DrawTarget for a display without a framebuffer that supports hardware accelerated drawing of styled Rectangles.

The default implementations of draw_rectangle as well as other shape drawing methods (draw_circle, etc) defer to draw_iter internally. In this example, the default implementation of draw_rectangle is overridden to allow usage of accelerated draw commands specific to the targeted hardware.

As this example doesn’t use a framebuffer, a “flush” operation is not required. All draw operations are performed in “immediate mode” directly on the display. As each drawing operation requires communication with the display that may fail, a custom error type CommError is introduced.

/// SPI communication error
#[derive(Debug)]
struct CommError;

/// A fake display which uses hardware drawing commands instead of a framebuffer
struct FastExampleDisplay {
    iface: SPI1,
}

impl FastExampleDisplay {
    /// Draw a rectangle using hardware accelerated commands
    pub fn fast_rectangle(
        &self,
        rect: &Styled<Rectangle, PrimitiveStyle<Gray8>>,
    ) -> Result<(), CommError> {
        // Send rectangle drawing commands to the display

        Ok(())
    }
}

impl DrawTarget<Gray8> for FastExampleDisplay {
    type Error = CommError;

    /// Draw a `pixel` that has a color defined as `Gray8`
    fn draw_pixel(&mut self, pixel: Pixel<Gray8>) -> Result<(), Self::Error> {
        let Pixel(coord, color) = pixel;

        // Send commands directly to the display to set an individual pixel to the given color

        Ok(())
    }

    fn size(&self) -> Size {
        Size::new(64, 64)
    }

    /// Use the accelerated method when drawing rectangles
    ///
    /// This method overrides the default implementation. If `fast_rectangle()` fails, the error
    /// will be propagated through this method.
    fn draw_rectangle(
        &mut self,
        item: &Styled<Rectangle, PrimitiveStyle<Gray8>>,
    ) -> Result<(), Self::Error> {
        self.fast_rectangle(item)
    }
}

let mut display = FastExampleDisplay { iface: SPI1 };

// Draw a rectangle from (10, 20) to (30, 40) with a white stroke
let rect = egrectangle!(
    top_left = (10, 20),
    bottom_right = (30, 40),
    style = primitive_style!(stroke_color = Gray8::WHITE, stroke_width = 1)
)
.draw(&mut display)?;

// Draw a rectangle on the display using accelerated `draw_rectangle()` function

Required Associated Types§

Source

type Error

Error type to return when a drawing operation fails.

This error is returned if an error occurred during a drawing operation. This mainly applies to drivers that need to communicate with the display for each drawing operation, where a communication error can occur. For drivers that use an internal framebuffer where drawing operations can never fail, core::convert::Infallible can instead be used as the Error type.

Required Methods§

Source

fn draw_pixel(&mut self, item: Pixel<C>) -> Result<(), Self::Error>

Draws a pixel on the display.

Source

fn size(&self) -> Size

Returns the dimensions of the DrawTarget in pixels.

Provided Methods§

Source

fn draw_iter<T>(&mut self, item: T) -> Result<(), Self::Error>
where T: IntoIterator<Item = Pixel<C>>,

Draws an object from an iterator over its pixels.

Source

fn clear(&mut self, color: C) -> Result<(), Self::Error>
where Self: Sized,

Clears the display with the supplied color.

This default implementation can be replaced if the implementing driver provides an accelerated clearing method.

Source

fn draw_line( &mut self, item: &Styled<Line, PrimitiveStyle<C>>, ) -> Result<(), Self::Error>

Draws a styled line primitive.

This default trait method can be overridden if a display provides hardware-accelerated methods for drawing lines.

§Caution

This method should not be called directly from application code. It is used to define the internals of the draw method used for the Styled Line primitive. To draw a line, call draw on a Styled<Line> object.

Source

fn draw_triangle( &mut self, item: &Styled<Triangle, PrimitiveStyle<C>>, ) -> Result<(), Self::Error>

Draws a styled triangle primitive.

This default trait method can be overridden if a display provides hardware-accelerated methods for drawing triangles.

§Caution

This method should not be called directly from application code. It is used to define the internals of the draw method used for the Styled Triangle primitive. To draw a triangle, call draw on a Styled<Triangle> object.

Source

fn draw_rectangle( &mut self, item: &Styled<Rectangle, PrimitiveStyle<C>>, ) -> Result<(), Self::Error>

Draws a styled rectangle primitive.

This default trait method can be overridden if a display provides hardware-accelerated methods for drawing rectangle.

§Caution

This method should not be called directly from application code. It is used to define the internals of the draw method used for the Styled Rectangle primitive. To draw a rectangle, call draw on a Styled<Rectangle> object.

Source

fn draw_circle( &mut self, item: &Styled<Circle, PrimitiveStyle<C>>, ) -> Result<(), Self::Error>

Draws a styled circle primitive.

This default trait method can be overridden if a display provides hardware-accelerated methods for drawing circles.

§Caution

This method should not be called directly from application code. It is used to define the internals of the draw method used for the Styled Circle primitive. To draw a circle, call draw on a Styled<Circle> object.

Source

fn draw_image<'a, 'b, I>( &mut self, item: &'a Image<'b, I, C>, ) -> Result<(), Self::Error>

Draws an image with known size

This default trait method can be overridden if a display provides hardware-accelerated methods for drawing an image with known size.

§Caution

This method should not be called directly from application code. It is used to define the internals of the draw method used for the Image primitive. To draw an image, call draw on a Image object.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§