1 | use crate::BitMapBackend; |
2 | use plotters_backend::DrawingBackend; |
3 | |
4 | #[inline (always)] |
5 | pub(super) fn blend(prev: &mut u8, new: u8, a: u64) { |
6 | if new > *prev { |
7 | *prev += (u64::from(new - *prev) * a / 256) as u8 |
8 | } else { |
9 | *prev -= (u64::from(*prev - new) * a / 256) as u8 |
10 | } |
11 | } |
12 | |
13 | /// The trait that describes some details about a particular pixel format |
14 | pub trait PixelFormat: Sized { |
15 | /// Number of bytes per pixel |
16 | const PIXEL_SIZE: usize; |
17 | |
18 | /// Number of effective bytes per pixel, e.g. for BGRX pixel format, the size of pixel |
19 | /// is 4 but the effective size is 3, since the 4th byte isn't used |
20 | const EFFECTIVE_PIXEL_SIZE: usize; |
21 | |
22 | /// Encoding a pixel and returns the idx-th byte for the pixel |
23 | fn byte_at(r: u8, g: u8, b: u8, a: u64, idx: usize) -> u8; |
24 | |
25 | /// Decode a pixel at the given location |
26 | fn decode_pixel(data: &[u8]) -> (u8, u8, u8, u64); |
27 | |
28 | /// The fast alpha blending algorithm for this pixel format |
29 | /// |
30 | /// - `target`: The target bitmap backend |
31 | /// - `upper_left`: The upper-left coord for the rect |
32 | /// - `bottom_right`: The bottom-right coord for the rect |
33 | /// - `r`, `g`, `b`, `a`: The blending color and alpha value |
34 | fn blend_rect_fast( |
35 | target: &mut BitMapBackend<'_, Self>, |
36 | upper_left: (i32, i32), |
37 | bottom_right: (i32, i32), |
38 | r: u8, |
39 | g: u8, |
40 | b: u8, |
41 | a: f64, |
42 | ); |
43 | |
44 | /// The fast vertical line filling algorithm |
45 | /// |
46 | /// - `target`: The target bitmap backend |
47 | /// - `x`: the X coordinate for the entire line |
48 | /// - `ys`: The range of y coord |
49 | /// - `r`, `g`, `b`: The blending color and alpha value |
50 | fn fill_vertical_line_fast( |
51 | target: &mut BitMapBackend<'_, Self>, |
52 | x: i32, |
53 | ys: (i32, i32), |
54 | r: u8, |
55 | g: u8, |
56 | b: u8, |
57 | ) { |
58 | let (w, h) = target.get_size(); |
59 | let w = w as i32; |
60 | let h = h as i32; |
61 | |
62 | // Make sure we are in the range |
63 | if x < 0 || x >= w { |
64 | return; |
65 | } |
66 | |
67 | let dst = target.get_raw_pixel_buffer(); |
68 | let (mut y0, mut y1) = ys; |
69 | if y0 > y1 { |
70 | std::mem::swap(&mut y0, &mut y1); |
71 | } |
72 | // And check the y axis isn't out of bound |
73 | y0 = y0.max(0); |
74 | y1 = y1.min(h - 1); |
75 | // This is ok because once y0 > y1, there won't be any iteration anymore |
76 | for y in y0..=y1 { |
77 | for idx in 0..Self::EFFECTIVE_PIXEL_SIZE { |
78 | dst[(y * w + x) as usize * Self::PIXEL_SIZE + idx] = Self::byte_at(r, g, b, 0, idx); |
79 | } |
80 | } |
81 | } |
82 | |
83 | /// The fast rectangle filling algorithm |
84 | /// |
85 | /// - `target`: The target bitmap backend |
86 | /// - `upper_left`: The upper-left coord for the rect |
87 | /// - `bottom_right`: The bottom-right coord for the rect |
88 | /// - `r`, `g`, `b`: The filling color |
89 | fn fill_rect_fast( |
90 | target: &mut BitMapBackend<'_, Self>, |
91 | upper_left: (i32, i32), |
92 | bottom_right: (i32, i32), |
93 | r: u8, |
94 | g: u8, |
95 | b: u8, |
96 | ); |
97 | |
98 | #[inline (always)] |
99 | /// Drawing a single pixel in this format |
100 | /// |
101 | /// - `target`: The target bitmap backend |
102 | /// - `point`: The coord of the point |
103 | /// - `r`, `g`, `b`: The filling color |
104 | /// - `alpha`: The alpha value |
105 | fn draw_pixel( |
106 | target: &mut BitMapBackend<'_, Self>, |
107 | point: (i32, i32), |
108 | (r, g, b): (u8, u8, u8), |
109 | alpha: f64, |
110 | ) { |
111 | let (x, y) = (point.0 as usize, point.1 as usize); |
112 | let (w, _) = target.get_size(); |
113 | let buf = target.get_raw_pixel_buffer(); |
114 | let w = w as usize; |
115 | let base = (y * w + x) * Self::PIXEL_SIZE; |
116 | |
117 | if base < buf.len() { |
118 | unsafe { |
119 | if alpha >= 1.0 - 1.0 / 256.0 { |
120 | for idx in 0..Self::EFFECTIVE_PIXEL_SIZE { |
121 | *buf.get_unchecked_mut(base + idx) = Self::byte_at(r, g, b, 0, idx); |
122 | } |
123 | } else { |
124 | if alpha <= 0.0 { |
125 | return; |
126 | } |
127 | |
128 | let alpha = (alpha * 256.0).floor() as u64; |
129 | for idx in 0..Self::EFFECTIVE_PIXEL_SIZE { |
130 | blend( |
131 | buf.get_unchecked_mut(base + idx), |
132 | Self::byte_at(r, g, b, 0, idx), |
133 | alpha, |
134 | ); |
135 | } |
136 | } |
137 | } |
138 | } |
139 | } |
140 | |
141 | /// Indicates if this pixel format can be saved as image. |
142 | /// Note: Currently we only using RGB pixel format in the image crate, but later we may lift |
143 | /// this restriction |
144 | /// |
145 | /// - `returns`: If the image can be saved as image file |
146 | fn can_be_saved() -> bool { |
147 | false |
148 | } |
149 | } |
150 | |