plotters_bitmap/bitmap_pixel/
pixel_format.rs

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}