1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::drawing::backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
use crate::style::{Color, RGBAColor};
use image::{ImageError, Rgb, RgbImage};
use std::path::Path;
enum Target<'a> {
File(&'a Path),
Buffer,
}
pub struct BitMapBackend<'a> {
target: Target<'a>,
img: RgbImage,
saved: bool,
}
impl<'a> BitMapBackend<'a> {
pub fn new<T: AsRef<Path> + ?Sized>(path: &'a T, dimension: (u32, u32)) -> Self {
Self {
target: Target::File(path.as_ref()),
img: RgbImage::new(dimension.0, dimension.1),
saved: false,
}
}
pub fn in_memory(dimension: (u32, u32)) -> Self {
Self {
target: Target::Buffer,
img: RgbImage::new(dimension.0, dimension.1),
saved: false,
}
}
pub fn try_into_buffer(mut self) -> Result<Vec<u8>, Self> {
match self.target {
Target::File(_) => Err(self),
Target::Buffer => {
let mut actual_img = RgbImage::new(1, 1);
std::mem::swap(&mut actual_img, &mut self.img);
Ok(actual_img.into_raw())
}
}
}
}
impl<'a> DrawingBackend for BitMapBackend<'a> {
type ErrorType = ImageError;
fn get_size(&self) -> (u32, u32) {
(self.img.width(), self.img.height())
}
fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<ImageError>> {
Ok(())
}
fn present(&mut self) -> Result<(), DrawingErrorKind<ImageError>> {
match self.target {
Target::File(path) => {
self.img
.save(&path)
.map_err(|x| DrawingErrorKind::DrawingError(ImageError::IoError(x)))?;
self.saved = true;
Ok(())
}
Target::Buffer => Ok(()),
}
}
fn draw_pixel(
&mut self,
point: BackendCoord,
color: &RGBAColor,
) -> Result<(), DrawingErrorKind<ImageError>> {
if point.0 as u32 >= self.img.width()
|| point.0 < 0
|| point.1 as u32 >= self.img.height()
|| point.1 < 0
{
return Ok(());
}
let alpha = color.alpha();
let rgb = color.rgb();
if alpha >= 1.0 {
self.img.put_pixel(
point.0 as u32,
point.1 as u32,
Rgb {
data: [rgb.0, rgb.1, rgb.2],
},
);
} else {
let pixel = self.img.get_pixel_mut(point.0 as u32, point.1 as u32);
let new_color = [rgb.0, rgb.1, rgb.2];
pixel
.data
.iter_mut()
.zip(&new_color)
.for_each(|(old, new)| {
*old = (f64::from(*old) * (1.0 - alpha) + f64::from(*new) * alpha).min(255.0)
as u8;
});
}
Ok(())
}
}
impl Drop for BitMapBackend<'_> {
fn drop(&mut self) {
if !self.saved {
self.present().expect("Unable to save the bitmap");
}
}
}