raqote-display 0.1.2

Implementation of embedded-graphics https://github.com/jamwaffles/embedded-graphics DrawTarget based on raqote https://github.com/jrmuizel/raqote.
Documentation
use embedded_graphics::{
    drawable::Pixel,
    geometry::{Dimensions, Size},
    image::{Image, ImageDimensions},
    pixelcolor::{Rgb565, Rgb888, RgbColor},
    prelude::*,
    primitives,
    style::{PrimitiveStyle, Styled},
    DrawTarget,
};

use raqote;

pub mod prelude;

/// This display is based on raqote's `DrawTarget` and is used as draw target for the embedded graphics crate.
///
/// # Example
///
/// ```rust
/// use RaqoteDisplay_display::prelude::*;
/// use embedded_graphics::{
///     image::{Image, ImageRaw, ImageRawLE},
///     pixelcolor::Rgb565,
///     prelude::*,
///     primitives::rectangle::Rectangle,
///     style::PrimitiveStyleBuilder,
///     };
///
/// let mut display = RaqoteDisplay::new(160, 128).unwrap();
///
/// let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLACK).build();
/// let black_backdrop = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style);
/// black_backdrop.draw(&mut display).unwrap();
///
/// // draw ferris
/// let image_raw: ImageRawLE<Rgb565> = ImageRaw::new(include_bytes!("../../../assets/ferris.raw"), 86, 64);
/// let image: Image<_, Rgb565> = Image::new(&image_raw, Point::new(34, 8));
/// image.draw(&mut display).unwrap();
/// ```
pub struct RaqoteDisplay {
    draw_target: raqote::DrawTarget,
    size: Size,
}

impl RaqoteDisplay {
    /// Creates a new display display with the given size.
    pub fn new(width: u32, height: u32) -> Result<Self, String> {
        Ok(RaqoteDisplay {
            draw_target: raqote::DrawTarget::new(width as i32, height as i32),
            size: Size::new(width, height),
        })
    }

    fn fill(&mut self, path: &raqote::Path, color: Rgb565) {
        self.draw_target.fill(
            path,
            &raqote::Source::from(convert_color(color)),
            &raqote::DrawOptions::default(),
        );
    }

    fn stroke(&mut self, path: &raqote::Path, color: Rgb565, stroke_width: u32) {
        self.draw_target.stroke(
            path,
            &raqote::Source::from(convert_color(color)),
            &raqote::StrokeStyle {
                width: stroke_width as f32,
                ..Default::default()
            },
            &raqote::DrawOptions::default(),
        );
    }

    pub fn data(&self) -> &[u32] {
        self.draw_target.get_data()
    }

    /// Pushes the frame buffer to the given surface and clears the frame buffer.
    pub fn flip(&mut self, surface: &mut [u32]) {
        surface.clone_from_slice(self.draw_target.get_data());
        self.draw_target = raqote::DrawTarget::new(self.size.width as i32, self.size.height as i32);
    }
}

impl DrawTarget<Rgb565> for RaqoteDisplay {
    type Error = String;

    fn draw_pixel(&mut self, pixel: Pixel<Rgb565>) -> Result<(), Self::Error> {
        self.draw_target.fill_rect(
            pixel.0.x as f32,
            pixel.0.y as f32,
            1.,
            1.,
            &raqote::Source::from(convert_color(pixel.1)),
            &raqote::DrawOptions::default(),
        );

        Ok(())
    }

    fn draw_line(
        &mut self,
        item: &Styled<primitives::Line, PrimitiveStyle<Rgb565>>,
    ) -> Result<(), Self::Error> {
        let line = item.primitive;
        let style = item.style;

        let mut path_builder = raqote::PathBuilder::new();
        path_builder.move_to(line.start.x as f32, line.start.y as f32);
        path_builder.line_to(line.end.x as f32, line.end.y as f32);

        let path = path_builder.finish();

        if let Some(fill_color) = style.fill_color {
            self.fill(&path, fill_color);
        }

        if let Some(stroke_color) = style.stroke_color {
            self.stroke(&path, stroke_color, style.stroke_width);
        }

        Ok(())
    }

    fn draw_rectangle(
        &mut self,
        item: &Styled<primitives::Rectangle, PrimitiveStyle<Rgb565>>,
    ) -> Result<(), Self::Error> {
        let rectangle = item.primitive;
        let style = item.style;

        let width = (rectangle.bottom_right.x - rectangle.top_left.x) as f32;
        let height = (rectangle.bottom_right.y - rectangle.top_left.y) as f32;

        if let Some(fill_color) = style.fill_color {
            self.draw_target.fill_rect(
                rectangle.top_left().x as f32,
                rectangle.top_left().y as f32,
                width,
                height,
                &raqote::Source::from(convert_color(fill_color)),
                &raqote::DrawOptions::default(),
            );
        }

        if let Some(stroke_color) = style.stroke_color {
            let mut path_builder = raqote::PathBuilder::new();
            path_builder.rect(
                rectangle.top_left().x as f32,
                rectangle.top_left().y as f32,
                width,
                height,
            );

            self.stroke(&path_builder.finish(), stroke_color, style.stroke_width);
        }

        Ok(())
    }

    fn draw_circle(
        &mut self,
        item: &Styled<primitives::Circle, PrimitiveStyle<Rgb565>>,
    ) -> Result<(), Self::Error> {
        let circle = item.primitive;
        let style = item.style;

        let mut path_builder = raqote::PathBuilder::new();
        path_builder.arc(
            circle.center.x as f32,
            circle.center.y as f32,
            circle.radius as f32,
            0.0,
            2.0 * std::f32::consts::PI,
        );

        let path = path_builder.finish();

        if let Some(fill_color) = style.fill_color {
            self.fill(&path, fill_color);
        }

        if let Some(stroke_color) = style.stroke_color {
            self.stroke(&path, stroke_color, style.stroke_width);
        }

        Ok(())
    }

    fn draw_image<'a, 'b, I>(&mut self, item: &'a Image<'b, I, Rgb565>) -> Result<(), Self::Error>
    where
        &'b I: IntoPixelIter<Rgb565>,
        I: ImageDimensions,
    {
        let mut pixels = vec![];

        for pixel in item {
            let color = convert_color(pixel.1);

            pixels.push(
                0xFF00_0000
                    | ((color.r() as u32) << 16)
                    | ((color.g() as u32) << 8)
                    | (color.b() as u32),
            );
        }

        let image = raqote::Image {
            width: item.size().width as i32,
            height: item.size().height as i32,
            data: &pixels,
        };

        self.draw_target.draw_image_at(
            item.top_left().x as f32,
            item.top_left().y as f32,
            &image,
            &raqote::DrawOptions::default(),
        );

        Ok(())
    }

    fn size(&self) -> Size {
        self.size
    }
}

fn convert_color(color: Rgb565) -> raqote::Color {
    let color: Rgb888 = Rgb888::from(color);
    raqote::Color::new(255, color.r(), color.g(), color.b())
}