• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
2 use image::{DynamicImage, GenericImageView};
3 
4 use super::{Drawable, PointCollection};
5 use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
6 
7 use plotters_bitmap::bitmap_pixel::{PixelFormat, RGBPixel};
8 
9 #[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
10 use plotters_bitmap::bitmap_pixel::BGRXPixel;
11 
12 use plotters_bitmap::BitMapBackend;
13 
14 use std::borrow::Borrow;
15 use std::marker::PhantomData;
16 
17 enum Buffer<'a> {
18     Owned(Vec<u8>),
19     Borrowed(&'a [u8]),
20     BorrowedMut(&'a mut [u8]),
21 }
22 
23 impl<'a> Borrow<[u8]> for Buffer<'a> {
borrow(&self) -> &[u8]24     fn borrow(&self) -> &[u8] {
25         self.as_ref()
26     }
27 }
28 
29 impl AsRef<[u8]> for Buffer<'_> {
as_ref(&self) -> &[u8]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 
39 impl<'a> Buffer<'a> {
to_mut(&mut self) -> &mut [u8]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
57 pub struct BitMapElement<'a, Coord, P: PixelFormat = RGBPixel> {
58     image: Buffer<'a>,
59     size: (u32, u32),
60     pos: Coord,
61     phantom: PhantomData<P>,
62 }
63 
64 impl<'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
new(pos: Coord, size: (u32, u32)) -> Self70     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`.
with_owned_buffer(pos: Coord, size: (u32, u32), buf: Vec<u8>) -> Option<Self>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`.
with_mut(pos: Coord, size: (u32, u32), buf: &'a mut [u8]) -> Option<Self>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`.
with_ref(pos: Coord, size: (u32, u32), buf: &'a [u8]) -> Option<Self>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
copy_to<Coord2>(&self, pos: Coord2) -> BitMapElement<Coord2, P>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
move_to(&mut self, pos: Coord)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
as_bitmap_backend(&mut self) -> BitMapBackend<P>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"))]
168 impl<'a, Coord> From<(Coord, DynamicImage)> for BitMapElement<'a, Coord, RGBPixel> {
from((pos, image): (Coord, DynamicImage)) -> Self169     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"))]
182 impl<'a, Coord> From<(Coord, DynamicImage)> for BitMapElement<'a, Coord, BGRXPixel> {
from((pos, image): (Coord, DynamicImage)) -> Self183     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 
195 impl<'a, 'b, Coord> PointCollection<'a, Coord> for &'a BitMapElement<'b, Coord> {
196     type Point = &'a Coord;
197     type IntoIter = std::iter::Once<&'a Coord>;
point_iter(self) -> Self::IntoIter198     fn point_iter(self) -> Self::IntoIter {
199         std::iter::once(&self.pos)
200     }
201 }
202 
203 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>>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 }
217