1 #![cfg(feature = "bitmap")]
2 
3 use jni_sys::{jobject, JNIEnv};
4 use num_enum::{IntoPrimitive, TryFromPrimitive};
5 use std::{convert::TryInto, mem::MaybeUninit, ptr::NonNull};
6 
7 #[cfg(feature = "hardware_buffer")]
8 use crate::hardware_buffer::HardwareBuffer;
9 
10 #[repr(i32)]
11 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
12 pub enum BitmapError {
13     Unknown,
14     AllocationFailed = ffi::ANDROID_BITMAP_RESULT_ALLOCATION_FAILED,
15     BadParameter = ffi::ANDROID_BITMAP_RESULT_BAD_PARAMETER,
16     JniException = ffi::ANDROID_BITMAP_RESULT_JNI_EXCEPTION,
17 }
18 
19 pub type BitmapResult<T, E = BitmapError> = std::result::Result<T, E>;
20 
21 impl BitmapError {
from_status<T>(status: i32, on_success: impl FnOnce() -> T) -> BitmapResult<T>22     pub(crate) fn from_status<T>(status: i32, on_success: impl FnOnce() -> T) -> BitmapResult<T> {
23         Err(match status {
24             ffi::ANDROID_BITMAP_RESULT_SUCCESS => return Ok(on_success()),
25             ffi::ANDROID_BITMAP_RESULT_ALLOCATION_FAILED => BitmapError::AllocationFailed,
26             ffi::ANDROID_BITMAP_RESULT_BAD_PARAMETER => BitmapError::BadParameter,
27             ffi::ANDROID_BITMAP_RESULT_JNI_EXCEPTION => BitmapError::JniException,
28             _ => BitmapError::Unknown,
29         })
30     }
31 }
32 
construct<T>(with_ptr: impl FnOnce(*mut T) -> i32) -> BitmapResult<T>33 fn construct<T>(with_ptr: impl FnOnce(*mut T) -> i32) -> BitmapResult<T> {
34     let mut result = MaybeUninit::uninit();
35     let status = with_ptr(result.as_mut_ptr());
36     BitmapError::from_status(status, || unsafe { result.assume_init() })
37 }
38 
39 #[repr(u32)]
40 #[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
41 #[allow(non_camel_case_types)]
42 pub enum BitmapFormat {
43     NONE = ffi::AndroidBitmapFormat_ANDROID_BITMAP_FORMAT_NONE,
44     RGBA_8888 = ffi::AndroidBitmapFormat_ANDROID_BITMAP_FORMAT_RGBA_8888,
45     RGB_565 = ffi::AndroidBitmapFormat_ANDROID_BITMAP_FORMAT_RGB_565,
46     #[deprecated = "Deprecated in API level 13. Because of the poor quality of this configuration, it is advised to use ARGB_8888 instead."]
47     RGBA_4444 = ffi::AndroidBitmapFormat_ANDROID_BITMAP_FORMAT_RGBA_4444,
48     A_8 = ffi::AndroidBitmapFormat_ANDROID_BITMAP_FORMAT_A_8,
49     RGBA_F16 = ffi::AndroidBitmapFormat_ANDROID_BITMAP_FORMAT_RGBA_F16,
50 }
51 
52 #[derive(Debug)]
53 pub struct AndroidBitmap {
54     env: *mut ffi::JNIEnv,
55     inner: ffi::jobject,
56 }
57 
58 impl AndroidBitmap {
59     /// Create an `AndroidBitmap` from JNI pointers
60     ///
61     /// # Safety
62     /// By calling this function, you assert that it these are valid pointers to JNI objects.
from_jni(env: *mut JNIEnv, bitmap: jobject) -> Self63     pub unsafe fn from_jni(env: *mut JNIEnv, bitmap: jobject) -> Self {
64         Self {
65             env: env as _,
66             inner: bitmap as _,
67         }
68     }
69 
get_info(&self) -> BitmapResult<AndroidBitmapInfo>70     pub fn get_info(&self) -> BitmapResult<AndroidBitmapInfo> {
71         let inner =
72             construct(|res| unsafe { ffi::AndroidBitmap_getInfo(self.env, self.inner, res) })?;
73 
74         Ok(AndroidBitmapInfo { inner })
75     }
76 
lock_pixels(&self) -> BitmapResult<*mut std::os::raw::c_void>77     pub fn lock_pixels(&self) -> BitmapResult<*mut std::os::raw::c_void> {
78         construct(|res| unsafe { ffi::AndroidBitmap_lockPixels(self.env, self.inner, res) })
79     }
80 
unlock_pixels(&self) -> BitmapResult<()>81     pub fn unlock_pixels(&self) -> BitmapResult<()> {
82         let status = unsafe { ffi::AndroidBitmap_unlockPixels(self.env, self.inner) };
83         BitmapError::from_status(status, || ())
84     }
85 
86     #[cfg(all(feature = "hardware_buffer", feature = "api-level-30"))]
get_hardware_buffer(&self) -> BitmapResult<HardwareBuffer>87     pub fn get_hardware_buffer(&self) -> BitmapResult<HardwareBuffer> {
88         unsafe {
89             let result =
90                 construct(|res| ffi::AndroidBitmap_getHardwareBuffer(self.env, self.inner, res))?;
91             let non_null = if cfg!(debug_assertions) {
92                 NonNull::new(result).expect("result should never be null")
93             } else {
94                 NonNull::new_unchecked(result)
95             };
96             Ok(HardwareBuffer::from_ptr(non_null))
97         }
98     }
99 }
100 
101 #[derive(Copy, Clone, Debug)]
102 pub struct AndroidBitmapInfo {
103     inner: ffi::AndroidBitmapInfo,
104 }
105 
106 // TODO: flesh out when API 30 is released
107 #[cfg(feature = "api-level-30")]
108 pub type AndroidBitmapInfoFlags = u32;
109 
110 impl AndroidBitmapInfo {
width(&self) -> u32111     pub fn width(&self) -> u32 {
112         self.inner.width
113     }
114 
height(&self) -> u32115     pub fn height(&self) -> u32 {
116         self.inner.height
117     }
118 
stride(&self) -> u32119     pub fn stride(&self) -> u32 {
120         self.inner.stride
121     }
122 
format(&self) -> BitmapFormat123     pub fn format(&self) -> BitmapFormat {
124         let format = self.inner.format as u32;
125         format.try_into().unwrap()
126     }
127 
128     #[cfg(feature = "api-level-30")]
flags(&self) -> AndroidBitmapInfoFlags129     pub fn flags(&self) -> AndroidBitmapInfoFlags {
130         self.inner.flags
131     }
132 }
133