plotters_unsable/drawing/backend_impl/
bitmap.rs

1use crate::drawing::backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
2use crate::style::Color;
3use image::{ImageError, Rgb, RgbImage};
4
5use std::path::Path;
6
7/// The backend that drawing a bitmap
8pub struct BitMapBackend<'a> {
9    /// The path to the image
10    path: &'a Path,
11    /// The image object
12    img: RgbImage,
13    /// Flag indicates if the bitmap has been saved
14    saved: bool,
15}
16
17impl<'a> BitMapBackend<'a> {
18    /// Create a new bitmap backend
19    pub fn new<T: AsRef<Path> + ?Sized>(path: &'a T, dimension: (u32, u32)) -> Self {
20        Self {
21            path: path.as_ref(),
22            img: RgbImage::new(dimension.0, dimension.1),
23            saved: false,
24        }
25    }
26}
27
28impl<'a> DrawingBackend for BitMapBackend<'a> {
29    type ErrorType = ImageError;
30
31    fn get_size(&self) -> (u32, u32) {
32        (self.img.width(), self.img.height())
33    }
34
35    fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<ImageError>> {
36        Ok(())
37    }
38
39    fn present(&mut self) -> Result<(), DrawingErrorKind<ImageError>> {
40        self.img
41            .save(&self.path)
42            .map_err(|x| DrawingErrorKind::DrawingError(ImageError::IoError(x)))?;
43        self.saved = true;
44        Ok(())
45    }
46
47    fn draw_pixel<C: Color>(
48        &mut self,
49        point: BackendCoord,
50        color: &C,
51    ) -> Result<(), DrawingErrorKind<ImageError>> {
52        if point.0 as u32 >= self.img.width()
53            || point.0 < 0
54            || point.1 as u32 >= self.img.height()
55            || point.1 < 0
56        {
57            return Ok(());
58        }
59
60        let alpha = color.alpha();
61        let rgb = color.rgb();
62
63        if alpha >= 1.0 {
64            self.img.put_pixel(
65                point.0 as u32,
66                point.1 as u32,
67                Rgb {
68                    data: [rgb.0, rgb.1, rgb.2],
69                },
70            );
71        } else {
72            let pixel = self.img.get_pixel_mut(point.0 as u32, point.1 as u32);
73
74            let new_color = [rgb.0, rgb.1, rgb.2];
75
76            pixel
77                .data
78                .iter_mut()
79                .zip(&new_color)
80                .for_each(|(old, new)| {
81                    *old = (f64::from(*old) * (1.0 - alpha) + f64::from(*new) * alpha).min(255.0)
82                        as u8;
83                });
84        }
85        Ok(())
86    }
87}
88
89impl Drop for BitMapBackend<'_> {
90    fn drop(&mut self) {
91        if !self.saved {
92            self.present().expect("Unable to save the bitmap");
93        }
94    }
95}