plotters_unsable/drawing/backend_impl/
bitmap.rs1use crate::drawing::backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
2use crate::style::Color;
3use image::{ImageError, Rgb, RgbImage};
4
5use std::path::Path;
6
7pub struct BitMapBackend<'a> {
9 path: &'a Path,
11 img: RgbImage,
13 saved: bool,
15}
16
17impl<'a> BitMapBackend<'a> {
18 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}