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