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