plotters_unstable/element/
image.rs

1#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
2use image::{DynamicImage, GenericImageView};
3
4use super::{Drawable, PointCollection};
5use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
6
7use plotters_bitmap::bitmap_pixel::{PixelFormat, RGBPixel};
8
9#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
10use plotters_bitmap::bitmap_pixel::BGRXPixel;
11
12use plotters_bitmap::BitMapBackend;
13
14use std::borrow::Borrow;
15use std::marker::PhantomData;
16
17enum Buffer<'a> {
18    Owned(Vec<u8>),
19    Borrowed(&'a [u8]),
20    BorrowedMut(&'a mut [u8]),
21}
22
23impl<'a> Borrow<[u8]> for Buffer<'a> {
24    fn borrow(&self) -> &[u8] {
25        self.as_ref()
26    }
27}
28
29impl AsRef<[u8]> for Buffer<'_> {
30    fn as_ref(&self) -> &[u8] {
31        match self {
32            Buffer::Owned(owned) => owned.as_ref(),
33            Buffer::Borrowed(target) => target,
34            Buffer::BorrowedMut(target) => target,
35        }
36    }
37}
38
39impl<'a> Buffer<'a> {
40    fn to_mut(&mut self) -> &mut [u8] {
41        let owned = match self {
42            Buffer::Owned(owned) => return &mut owned[..],
43            Buffer::BorrowedMut(target) => return target,
44            Buffer::Borrowed(target) => {
45                let mut value = vec![];
46                value.extend_from_slice(target);
47                value
48            }
49        };
50
51        *self = Buffer::Owned(owned);
52        self.to_mut()
53    }
54}
55
56/// The element that contains a bitmap on it
57pub struct BitMapElement<'a, Coord, P: PixelFormat = RGBPixel> {
58    image: Buffer<'a>,
59    size: (u32, u32),
60    pos: Coord,
61    phantom: PhantomData<P>,
62}
63
64impl<'a, Coord, P: PixelFormat> BitMapElement<'a, Coord, P> {
65    /// Create a new empty bitmap element. This can be use as
66    /// the draw and blit pattern.
67    ///
68    /// - `pos`: The left upper coordinate for the element
69    /// - `size`: The size of the bitmap
70    pub fn new(pos: Coord, size: (u32, u32)) -> Self {
71        Self {
72            image: Buffer::Owned(vec![0; (size.0 * size.1) as usize * P::PIXEL_SIZE]),
73            size,
74            pos,
75            phantom: PhantomData,
76        }
77    }
78
79    /// Create a new bitmap element with an pre-allocated owned buffer, this function will
80    /// take the ownership of the buffer.
81    ///
82    /// - `pos`: The left upper coordinate of the elelent
83    /// - `size`: The size of the bitmap
84    /// - `buf`: The buffer to use
85    /// - **returns**: The newly created image element, if the buffer isn't fit the image
86    /// dimension, this will returns an `None`.
87    pub fn with_owned_buffer(pos: Coord, size: (u32, u32), buf: Vec<u8>) -> Option<Self> {
88        if buf.len() < (size.0 * size.1) as usize * P::PIXEL_SIZE {
89            return None;
90        }
91
92        Some(Self {
93            image: Buffer::Owned(buf),
94            size,
95            pos,
96            phantom: PhantomData,
97        })
98    }
99
100    /// Create a new bitmap element with a mut borrow to an existing buffer
101    ///
102    /// - `pos`: The left upper coordinate of the elelent
103    /// - `size`: The size of the bitmap
104    /// - `buf`: The buffer to use
105    /// - **returns**: The newly created image element, if the buffer isn't fit the image
106    /// dimension, this will returns an `None`.
107    pub fn with_mut(pos: Coord, size: (u32, u32), buf: &'a mut [u8]) -> Option<Self> {
108        if buf.len() < (size.0 * size.1) as usize * P::PIXEL_SIZE {
109            return None;
110        }
111
112        Some(Self {
113            image: Buffer::BorrowedMut(buf),
114            size,
115            pos,
116            phantom: PhantomData,
117        })
118    }
119
120    /// Create a new bitmap element with a shared borrowed buffer. This means if we want to modifiy
121    /// the content of the image, the buffer is automatically copied
122    ///
123    /// - `pos`: The left upper coordinate of the elelent
124    /// - `size`: The size of the bitmap
125    /// - `buf`: The buffer to use
126    /// - **returns**: The newly created image element, if the buffer isn't fit the image
127    /// dimension, this will returns an `None`.
128    pub fn with_ref(pos: Coord, size: (u32, u32), buf: &'a [u8]) -> Option<Self> {
129        if buf.len() < (size.0 * size.1) as usize * P::PIXEL_SIZE {
130            return None;
131        }
132
133        Some(Self {
134            image: Buffer::Borrowed(buf),
135            size,
136            pos,
137            phantom: PhantomData,
138        })
139    }
140
141    /// Copy the existing bitmap element to another location
142    ///
143    /// - `pos`: The new location to copy
144    pub fn copy_to<Coord2>(&self, pos: Coord2) -> BitMapElement<Coord2, P> {
145        BitMapElement {
146            image: Buffer::Borrowed(self.image.borrow()),
147            size: self.size,
148            pos,
149            phantom: PhantomData,
150        }
151    }
152
153    /// Move the existing bitmap element to a new position
154    ///
155    /// - `pos`: The new position
156    pub fn move_to(&mut self, pos: Coord) {
157        self.pos = pos;
158    }
159
160    /// Make the bitmap element as a bitmap backend, so that we can use
161    /// plotters drawing functionality on the bitmap element
162    pub fn as_bitmap_backend(&mut self) -> BitMapBackend<P> {
163        BitMapBackend::with_buffer_and_format(self.image.to_mut(), self.size).unwrap()
164    }
165}
166
167#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
168impl<'a, Coord> From<(Coord, DynamicImage)> for BitMapElement<'a, Coord, RGBPixel> {
169    fn from((pos, image): (Coord, DynamicImage)) -> Self {
170        let (w, h) = image.dimensions();
171        let rgb_image = image.to_rgb().into_raw();
172        Self {
173            pos,
174            image: Buffer::Owned(rgb_image),
175            size: (w, h),
176            phantom: PhantomData,
177        }
178    }
179}
180
181#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
182impl<'a, Coord> From<(Coord, DynamicImage)> for BitMapElement<'a, Coord, BGRXPixel> {
183    fn from((pos, image): (Coord, DynamicImage)) -> Self {
184        let (w, h) = image.dimensions();
185        let rgb_image = image.to_bgra().into_raw();
186        Self {
187            pos,
188            image: Buffer::Owned(rgb_image),
189            size: (w, h),
190            phantom: PhantomData,
191        }
192    }
193}
194
195impl<'a, 'b, Coord> PointCollection<'a, Coord> for &'a BitMapElement<'b, Coord> {
196    type Point = &'a Coord;
197    type IntoIter = std::iter::Once<&'a Coord>;
198    fn point_iter(self) -> Self::IntoIter {
199        std::iter::once(&self.pos)
200    }
201}
202
203impl<'a, Coord, DB: DrawingBackend> Drawable<DB> for BitMapElement<'a, Coord> {
204    fn draw<I: Iterator<Item = BackendCoord>>(
205        &self,
206        mut points: I,
207        backend: &mut DB,
208        _: (u32, u32),
209    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
210        if let Some((x, y)) = points.next() {
211            // TODO: convert the pixel format when needed
212            return backend.blit_bitmap((x, y), self.size, self.image.as_ref());
213        }
214        Ok(())
215    }
216}