1use std::{
4 ffi::{c_void, CString},
5 ops::{Deref, DerefMut},
6 path::Path,
7 slice,
8 sync::Arc,
9};
10
11use crate::Library;
12
13#[derive(Debug, thiserror::Error)]
15pub enum BitmapError {
16 #[error("Creation of bitmap failed because Ultralight returned a null pointer")]
18 NullReference,
19 #[error(
21 "Creation of bitmap failed because it required {required} bytes, but got {got} bytes only"
22 )]
23 PixelBufferSizeMismatch { got: usize, required: usize },
24 #[error("Tried to swap red and blue channels on an unsupported format")]
26 UnsupportedOperationForPixelFormat,
27 #[error("Could not write bitmap to PNG successfully")]
29 FailedPngWrite,
30 #[error("Could not create bitmap because its empty")]
32 EmptyBitmap,
33}
34
35type BitmapResult<T> = std::result::Result<T, BitmapError>;
36
37#[derive(Debug, Clone, Copy)]
38pub enum BitmapFormat {
40 A8Unorm = ul_sys::ULBitmapFormat_kBitmapFormat_A8_UNORM as isize,
46
47 Bgra8UnormSrgb = ul_sys::ULBitmapFormat_kBitmapFormat_BGRA8_UNORM_SRGB as isize,
53}
54
55impl TryFrom<ul_sys::ULBitmapFormat> for BitmapFormat {
56 type Error = ();
57
58 fn try_from(format: ul_sys::ULBitmapFormat) -> Result<Self, Self::Error> {
59 match format {
60 ul_sys::ULBitmapFormat_kBitmapFormat_A8_UNORM => Ok(BitmapFormat::A8Unorm),
61 ul_sys::ULBitmapFormat_kBitmapFormat_BGRA8_UNORM_SRGB => {
62 Ok(BitmapFormat::Bgra8UnormSrgb)
63 }
64 _ => Err(()),
65 }
66 }
67}
68
69impl BitmapFormat {
70 pub fn bytes_per_pixel(&self) -> u32 {
72 match self {
73 BitmapFormat::A8Unorm => 1,
74 BitmapFormat::Bgra8UnormSrgb => 4,
75 }
76 }
77}
78
79pub struct PixelsGuard<'a> {
84 lock: &'a mut Bitmap,
85 pixels: &'a mut [u8],
86}
87
88impl<'a> PixelsGuard<'a> {
89 unsafe fn new(lock: &'a mut Bitmap, pixels: &'a mut [u8]) -> PixelsGuard<'a> {
90 PixelsGuard { lock, pixels }
91 }
92}
93
94impl Deref for PixelsGuard<'_> {
95 type Target = [u8];
96
97 fn deref(&self) -> &[u8] {
98 self.pixels
99 }
100}
101
102impl DerefMut for PixelsGuard<'_> {
103 fn deref_mut(&mut self) -> &mut [u8] {
104 self.pixels
105 }
106}
107
108impl Drop for PixelsGuard<'_> {
109 fn drop(&mut self) {
110 unsafe {
111 self.lock.raw_unlock_pixels();
112 }
113 }
114}
115
116pub struct Bitmap {
118 lib: Arc<Library>,
119 internal: ul_sys::ULBitmap,
120 need_to_destroy: bool,
121}
122
123impl Bitmap {
124 pub(crate) unsafe fn from_raw(lib: Arc<Library>, raw: ul_sys::ULBitmap) -> Option<Self> {
125 if raw.is_null() {
126 return None;
127 }
128
129 Some(Bitmap {
130 lib,
131 internal: raw,
132 need_to_destroy: false,
133 })
134 }
135
136 pub(crate) unsafe fn to_ul(&self) -> ul_sys::ULBitmap {
137 self.internal
138 }
139
140 pub fn create_empty(lib: Arc<Library>) -> BitmapResult<Self> {
142 let internal = unsafe { lib.ultralight().ulCreateEmptyBitmap() };
143
144 if internal.is_null() {
145 Err(BitmapError::NullReference)
146 } else {
147 Ok(Self {
148 lib,
149 internal,
150 need_to_destroy: true,
151 })
152 }
153 }
154
155 pub fn create(
164 lib: Arc<Library>,
165 width: usize,
166 height: usize,
167 format: BitmapFormat,
168 ) -> BitmapResult<Self> {
169 let internal = unsafe {
170 lib.ultralight()
171 .ulCreateBitmap(width as u32, height as u32, format as u32)
172 };
173 if internal.is_null() {
174 Err(BitmapError::NullReference)
175 } else {
176 Ok(Self {
177 lib,
178 internal,
179 need_to_destroy: true,
180 })
181 }
182 }
183
184 pub fn create_from_pixels(
195 lib: Arc<Library>,
196 width: u32,
197 height: u32,
198 format: BitmapFormat,
199 pixels: &[u8],
200 ) -> BitmapResult<Self> {
201 let row_bytes = width * format.bytes_per_pixel();
202 let bytes_size = (height * row_bytes) as usize;
203 if pixels.len() != bytes_size {
204 return Err(BitmapError::PixelBufferSizeMismatch {
205 got: pixels.len(),
206 required: bytes_size,
207 });
208 }
209 let internal = unsafe {
214 lib.ultralight().ulCreateBitmapFromPixels(
215 width,
216 height,
217 format as u32,
218 row_bytes,
219 pixels.as_ptr() as *const c_void,
220 pixels.len(),
221 true,
222 )
223 };
224 if internal.is_null() {
225 Err(BitmapError::NullReference)
226 } else {
227 Ok(Self {
228 lib,
229 internal,
230 need_to_destroy: true,
231 })
232 }
233 }
234
235 pub fn copy(&self) -> BitmapResult<Self> {
237 let internal = unsafe { self.lib.ultralight().ulCreateBitmapFromCopy(self.internal) };
238
239 if internal.is_null() {
240 Err(BitmapError::NullReference)
241 } else {
242 Ok(Self {
243 lib: self.lib.clone(),
244 internal,
245 need_to_destroy: true,
246 })
247 }
248 }
249}
250
251impl Bitmap {
252 pub fn width(&self) -> u32 {
254 unsafe { self.lib.ultralight().ulBitmapGetWidth(self.internal) }
255 }
256
257 pub fn height(&self) -> u32 {
259 unsafe { self.lib.ultralight().ulBitmapGetHeight(self.internal) }
260 }
261
262 pub fn format(&self) -> BitmapFormat {
264 unsafe { self.lib.ultralight().ulBitmapGetFormat(self.internal) }
265 .try_into()
266 .unwrap()
267 }
268
269 pub fn bpp(&self) -> u32 {
271 unsafe { self.lib.ultralight().ulBitmapGetBpp(self.internal) }
272 }
273
274 pub fn row_bytes(&self) -> u32 {
279 unsafe { self.lib.ultralight().ulBitmapGetRowBytes(self.internal) }
280 }
281
282 pub fn bytes_size(&self) -> usize {
286 unsafe { self.lib.ultralight().ulBitmapGetSize(self.internal) }
287 }
288
289 pub fn lock_pixels(&mut self) -> Option<PixelsGuard> {
293 let (raw_pixels, size) = unsafe {
294 self.lib.ultralight().ulBitmapLockPixels(self.internal);
295 (
296 self.lib.ultralight().ulBitmapRawPixels(self.internal),
297 self.lib.ultralight().ulBitmapGetSize(self.internal),
298 )
299 };
300
301 if raw_pixels.is_null() {
302 return None;
303 }
304
305 unsafe {
306 let data = slice::from_raw_parts_mut(raw_pixels as _, size);
307 Some(PixelsGuard::new(self, data))
308 }
309 }
310
311 pub(crate) unsafe fn raw_unlock_pixels(&mut self) {
313 self.lib.ultralight().ulBitmapUnlockPixels(self.internal);
314 }
315
316 pub fn is_empty(&self) -> bool {
318 unsafe { self.lib.ultralight().ulBitmapIsEmpty(self.internal) }
319 }
320
321 pub fn erase(&self) {
323 unsafe { self.lib.ultralight().ulBitmapErase(self.internal) }
324 }
325
326 pub fn write_to_png<P: AsRef<Path>>(&self, path: P) -> BitmapResult<()> {
328 let c_path = CString::new(path.as_ref().to_str().unwrap()).unwrap();
329 let result = unsafe {
330 self.lib
331 .ultralight()
332 .ulBitmapWritePNG(self.internal, c_path.as_ptr())
333 };
334 if result {
335 Ok(())
336 } else {
337 Err(BitmapError::FailedPngWrite)
338 }
339 }
340
341 pub fn swap_red_blue_channels(&self) -> BitmapResult<()> {
345 if let BitmapFormat::Bgra8UnormSrgb = self.format() {
346 unsafe {
347 self.lib
348 .ultralight()
349 .ulBitmapSwapRedBlueChannels(self.internal)
350 }
351 Ok(())
352 } else {
353 Err(BitmapError::UnsupportedOperationForPixelFormat)
354 }
355 }
356}
357
358impl Drop for Bitmap {
359 fn drop(&mut self) {
360 if self.need_to_destroy {
361 unsafe { self.lib.ultralight().ulDestroyBitmap(self.internal) };
362 }
363 }
364}
365
366pub struct OwnedBitmap {
373 width: u32,
374 height: u32,
375 format: BitmapFormat,
376 bpp: u32,
377 row_bytes: u32,
378 bytes_size: usize,
379 pixels: Option<Vec<u8>>,
380 is_empty: bool,
381}
382
383impl OwnedBitmap {
384 pub fn from_bitmap(bitmap: &mut Bitmap) -> Option<Self> {
388 let width = bitmap.width();
389 let height = bitmap.height();
390 let format = bitmap.format();
391 let bpp = bitmap.bpp();
392 let row_bytes = bitmap.row_bytes();
393 let bytes_size = bitmap.bytes_size();
394 let is_empty = bitmap.is_empty();
395
396 let pixels = bitmap.lock_pixels().map(|v| v.to_vec());
397
398 Some(Self {
399 width,
400 height,
401 format,
402 bpp,
403 row_bytes,
404 bytes_size,
405 pixels,
406 is_empty,
407 })
408 }
409
410 pub fn to_bitmap(&self, lib: Arc<Library>) -> BitmapResult<Bitmap> {
416 if let Some(pixels) = self.pixels.as_ref() {
417 Bitmap::create_from_pixels(lib, self.width, self.height, self.format, pixels.as_slice())
418 } else {
419 Err(BitmapError::EmptyBitmap)
420 }
421 }
422
423 pub fn width(&self) -> u32 {
425 self.width
426 }
427
428 pub fn height(&self) -> u32 {
430 self.height
431 }
432
433 pub fn format(&self) -> BitmapFormat {
435 self.format
436 }
437
438 pub fn bpp(&self) -> u32 {
440 self.bpp
441 }
442
443 pub fn row_bytes(&self) -> u32 {
445 self.row_bytes
446 }
447
448 pub fn bytes_size(&self) -> usize {
450 self.bytes_size
451 }
452
453 pub fn pixels(&self) -> Option<&[u8]> {
455 self.pixels.as_deref()
456 }
457
458 pub fn pixels_mut(&mut self) -> Option<&mut [u8]> {
460 self.pixels.as_deref_mut()
461 }
462
463 pub fn is_empty(&self) -> bool {
465 self.is_empty
466 }
467}