ferroui_base/media/imaging/
writeable_bitmap.rs1use crate::media::imaging::bitmap_memory::BitmapMemory;
2use crate::media::imaging::pixel_format_readers::PixelFormatReader;
3use crate::media::imaging::{Bitmap, BitmapEncoderOptions, BitmapInterpolationMode, IBitmap};
4use crate::media::{DrawingContext, IImage, IImageBrushSource};
5use crate::platform::{self, AlphaFormat, IBitmapImpl, ILockedFramebuffer, IWriteableBitmapImpl, PixelFormat};
6use crate::utilities::RefCounted;
7use crate::{PixelRect, PixelSize, Rect, Size, Vector};
8use std::any::Any;
9use std::cell::{Cell, RefCell};
10use std::io::{Read, Write};
11use std::ops::Deref;
12use std::rc::Rc;
13
14pub struct WriteableBitmap {
16 base: Bitmap,
17 pixel_format_memory: Option<Rc<RefCell<BitmapMemory>>>,
19}
20
21impl Deref for WriteableBitmap {
22 type Target = Bitmap;
23
24 #[inline]
25 fn deref(&self) -> &Bitmap {
26 &self.base
27 }
28}
29
30impl WriteableBitmap {
31 pub fn new(
37 size: PixelSize,
38 dpi: Vector,
39 format: Option<PixelFormat>,
40 alpha_format: Option<AlphaFormat>,
41 ) -> WriteableBitmap {
42 let (platform_impl, pixel_format_memory) = Self::create_platform_impl(size, dpi, format, alpha_format);
43 Self::from_impl(platform_impl, pixel_format_memory)
44 }
45
46 fn from_impl(platform_impl: std::sync::Arc<dyn IWriteableBitmapImpl>, pixel_format_memory: Option<BitmapMemory>) -> Self {
47 Self {
48 base: Bitmap::from_impl(platform_impl),
49 pixel_format_memory: pixel_format_memory.map(|memory| Rc::new(RefCell::new(memory))),
50 }
51 }
52
53 pub fn from_pixels(
58 format: PixelFormat,
59 alpha_format: AlphaFormat,
60 data: &[u8],
61 size: PixelSize,
62 dpi: Vector,
63 stride: i32,
64 ) -> WriteableBitmap {
65 let result = Self::new(size, dpi, Some(format), Some(alpha_format));
66
67 let min_stride = (format.bits_per_pixel() as i32 * size.width + 7) / 8;
68 if min_stride > stride {
69 panic!("stride is out of range: {stride}");
70 }
71
72 let locked = result.lock();
73 let row_bytes = locked.row_bytes();
74 locked.with_data(&mut |dest| {
75 let min_stride = min_stride as usize;
76 for y in 0..size.height {
77 let dst = (row_bytes as i64 * y as i64) as usize;
78 let src = (stride as i64 * y as i64) as usize;
79 dest[dst..dst + min_stride].copy_from_slice(&data[src..src + min_stride]);
80 }
81 });
82 locked.dispose();
83
84 result
85 }
86
87 pub fn format(&self) -> Option<PixelFormat> {
89 match &self.pixel_format_memory {
90 Some(memory) => Some(memory.borrow().format()),
91 None => self.base.format(),
92 }
93 }
94
95 pub fn lock(&self) -> Rc<dyn ILockedFramebuffer> {
99 let platform_impl = self.base.platform_impl().item();
100 let Some(memory) = &self.pixel_format_memory else {
101 return platform_impl.as_readable_bitmap().expect("the platform bitmap is writeable").lock();
102 };
103
104 let (size, row_bytes, format, alpha_format) = {
105 let memory = memory.borrow();
106 (memory.size(), memory.row_bytes(), memory.format(), memory.alpha_format())
107 };
108
109 Rc::new(MemoryLockedFramebuffer {
110 memory: memory.clone(),
111 platform_impl,
112 size,
113 row_bytes,
114 dpi: self.dpi(),
115 format,
116 alpha_format,
117 disposed: Cell::new(false),
118 })
119 }
120
121 pub fn copy_pixels(&self, source_rect: PixelRect, buffer: &mut [u8], stride: i32) {
125 let fb = self.lock();
126 self.base.copy_pixels_core(source_rect, buffer, stride, &*fb);
127 fb.dispose();
128 }
129
130 pub fn decode(stream: &mut dyn Read) -> std::io::Result<WriteableBitmap> {
132 let ri = platform::render_interface();
133 Ok(Self::from_impl(ri.load_writeable_bitmap(stream)?, None))
134 }
135
136 pub fn decode_to_width(
139 stream: &mut dyn Read,
140 width: i32,
141 interpolation_mode: BitmapInterpolationMode,
142 ) -> std::io::Result<WriteableBitmap> {
143 let ri = platform::render_interface();
144 Ok(Self::from_impl(ri.load_writeable_bitmap_to_width(stream, width, interpolation_mode)?, None))
145 }
146
147 pub fn decode_to_height(
150 stream: &mut dyn Read,
151 height: i32,
152 interpolation_mode: BitmapInterpolationMode,
153 ) -> std::io::Result<WriteableBitmap> {
154 let ri = platform::render_interface();
155 Ok(Self::from_impl(ri.load_writeable_bitmap_to_height(stream, height, interpolation_mode)?, None))
156 }
157
158 fn create_platform_impl(
159 size: PixelSize,
160 dpi: Vector,
161 format: Option<PixelFormat>,
162 alpha_format: Option<AlphaFormat>,
163 ) -> (std::sync::Arc<dyn IWriteableBitmapImpl>, Option<BitmapMemory>) {
164 if size.width <= 0 || size.height <= 0 {
165 panic!("Size should be >= (1,1)");
166 }
167
168 let ri = platform::render_interface();
169
170 let final_format = format.unwrap_or_else(|| ri.default_pixel_format());
171 let mut final_alpha_format = alpha_format.unwrap_or_else(|| ri.default_alpha_format());
172
173 if ri.is_supported_bitmap_pixel_format(final_format) {
174 return (ri.create_writeable_bitmap(size, dpi, final_format, final_alpha_format), None);
175 }
176
177 if !PixelFormatReader::supports_format(final_format) {
178 panic!("Pixel format {final_format} is not supported");
179 }
180
181 final_alpha_format = if final_format.has_alpha() { final_alpha_format } else { AlphaFormat::Opaque };
182
183 let platform_impl = ri.create_writeable_bitmap(size, dpi, PixelFormat::RGBA8888, final_alpha_format);
184 (platform_impl, Some(BitmapMemory::new(final_format, final_alpha_format, size)))
185 }
186}
187
188struct MemoryLockedFramebuffer {
191 memory: Rc<RefCell<BitmapMemory>>,
192 platform_impl: std::sync::Arc<crate::platform::SharedBitmapImpl>,
193 size: PixelSize,
194 row_bytes: i32,
195 dpi: Vector,
196 format: PixelFormat,
197 alpha_format: AlphaFormat,
198 disposed: Cell<bool>,
199}
200
201impl ILockedFramebuffer for MemoryLockedFramebuffer {
202 fn address(&self) -> *mut u8 {
203 self.memory.borrow_mut().data_mut().as_mut_ptr()
204 }
205
206 fn with_data(&self, access: &mut dyn FnMut(&mut [u8])) {
207 access(self.memory.borrow_mut().data_mut());
208 }
209
210 fn size(&self) -> PixelSize {
211 self.size
212 }
213
214 fn row_bytes(&self) -> i32 {
215 self.row_bytes
216 }
217
218 fn dpi(&self) -> Vector {
219 self.dpi
220 }
221
222 fn format(&self) -> PixelFormat {
223 self.format
224 }
225
226 fn alpha_format(&self) -> AlphaFormat {
227 self.alpha_format
228 }
229
230 fn dispose(&self) {
231 if self.disposed.replace(true) {
232 return;
233 }
234 let inner = self.platform_impl.as_readable_bitmap().expect("the platform bitmap is writeable").lock();
235 let (alpha_format, row_bytes) = (inner.alpha_format(), inner.row_bytes());
236 let memory = self.memory.borrow();
237 inner.with_data(&mut |dest| memory.copy_to_rgba(alpha_format, dest, row_bytes));
238 inner.dispose();
239 }
240}
241
242impl IImage for WriteableBitmap {
243 fn size(&self) -> Size {
244 self.base.size()
245 }
246
247 fn draw(&self, context: &mut DrawingContext<'_>, source_rect: Rect, dest_rect: Rect) {
248 IImage::draw(&self.base, context, source_rect, dest_rect)
249 }
250
251 fn as_any(&self) -> &dyn Any {
252 self
253 }
254
255 fn as_bitmap(&self) -> Option<&dyn IBitmap> {
256 Some(self)
257 }
258}
259
260impl IBitmap for WriteableBitmap {
261 fn dpi(&self) -> Vector {
262 self.base.dpi()
263 }
264
265 fn pixel_size(&self) -> PixelSize {
266 self.base.pixel_size()
267 }
268
269 fn platform_impl(&self) -> &RefCounted<crate::platform::SharedBitmapImpl> {
270 self.base.platform_impl()
271 }
272
273 fn save(&self, stream: &mut dyn Write, options: &BitmapEncoderOptions) -> std::io::Result<()> {
274 self.base.save(stream, options)
275 }
276
277 fn dispose(&self) {
278 self.base.dispose()
279 }
280}
281
282impl IImageBrushSource for WriteableBitmap {
283 fn bitmap(&self) -> Option<&RefCounted<crate::platform::SharedBitmapImpl>> {
284 IImageBrushSource::bitmap(&self.base)
285 }
286}