1use crate::BitMapBackend;
2use plotters_backend::DrawingBackend;
3
4#[inline(always)]
5pub(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
14pub 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