]> git.nega.tv - josh/narcissus/commitdiff
Add basic safe wrapper for stb_image
authorJoshua Simmons <josh@nega.tv>
Sat, 17 Sep 2022 10:04:27 +0000 (12:04 +0200)
committerJoshua Simmons <josh@nega.tv>
Sat, 17 Sep 2022 10:04:27 +0000 (12:04 +0200)
Cargo.lock
ffi/stb_image-sys/src/lib.rs
narcissus-core/Cargo.toml
narcissus-core/src/image.rs [new file with mode: 0644]
narcissus-core/src/lib.rs

index b9e260c57bff61fca9cd2e860b4914e3243c41cf..d3f164701905993226b2af00553ed8faaa957a75 100644 (file)
@@ -24,6 +24,7 @@ dependencies = [
 name = "narcissus-core"
 version = "0.1.0"
 dependencies = [
+ "stb_image-sys",
 ]
 
 [[package]]
index ef08dd6c83629fc18201965c0a6bcec27439b9f1..ad2c0e40ee3a35e885824842397952a40f441a8d 100644 (file)
@@ -24,68 +24,68 @@ extern "C" {
     pub fn stbi_load_from_memory(
         buffer: *const c_uchar,
         len: c_int,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
         req_comp: c_int,
     ) -> *mut c_uchar;
 
     pub fn stbi_load(
         filename: *const c_char,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
         req_comp: c_int,
     ) -> *mut c_uchar;
 
     pub fn stbi_load_from_file(
         f: *mut libc::FILE,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
         req_comp: c_int,
     ) -> *mut c_uchar;
 
     pub fn stbi_load_from_callbacks(
-        clbk: *const stbi_io_callbacks,
+        clbk: &stbi_io_callbacks,
         user: *mut c_void,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
         req_comp: c_int,
     ) -> *mut c_uchar;
 
     pub fn stbi_loadf_from_memory(
         buffer: *const c_uchar,
         len: c_int,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
         req_comp: c_int,
     ) -> *mut c_float;
 
     pub fn stbi_loadf(
         filename: *const c_char,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
         req_comp: c_int,
     ) -> *mut c_float;
 
     pub fn stbi_loadf_from_file(
         f: *mut libc::FILE,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
         req_comp: c_int,
     ) -> *mut c_float;
 
     pub fn stbi_loadf_from_callbacks(
-        clbk: *const stbi_io_callbacks,
+        clbk: &stbi_io_callbacks,
         user: *mut c_void,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
         req_comp: c_int,
     ) -> *mut c_float;
 
@@ -97,7 +97,7 @@ extern "C" {
 
     pub fn stbi_ldr_to_hdr_scale(scale: c_float);
 
-    pub fn stbi_is_hdr_from_callbacks(clbk: *const stbi_io_callbacks, user: *mut c_void) -> c_int;
+    pub fn stbi_is_hdr_from_callbacks(clbk: &stbi_io_callbacks, user: *mut c_void) -> c_int;
 
     pub fn stbi_is_hdr_from_memory(buffer: *const c_uchar, len: c_int) -> c_int;
 
@@ -112,31 +112,31 @@ extern "C" {
     pub fn stbi_info_from_memory(
         buffer: *const c_uchar,
         len: c_int,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
     ) -> c_int;
 
     pub fn stbi_info_from_callbacks(
-        clbk: *const stbi_io_callbacks,
+        clbk: &stbi_io_callbacks,
         user: *mut c_void,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
     ) -> c_int;
 
     pub fn stbi_info(
         filename: *const c_char,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
     ) -> c_int;
 
     pub fn stbi_info_from_file(
         f: *mut libc::FILE,
-        x: *mut c_int,
-        y: *mut c_int,
-        comp: *mut c_int,
+        x: &mut c_int,
+        y: &mut c_int,
+        comp: &mut c_int,
     ) -> c_int;
 
     pub fn stbi_set_unpremultiply_on_load(flag_true_if_should_unpremultiply: c_int);
@@ -147,13 +147,13 @@ extern "C" {
         buffer: *const c_char,
         len: c_int,
         initial_size: c_int,
-        outlen: *mut c_int,
+        outlen: &mut c_int,
     ) -> *mut c_char;
 
     pub fn stbi_zlib_decode_malloc(
         buffer: *const c_char,
         len: c_int,
-        outlen: *mut c_int,
+        outlen: &mut c_int,
     ) -> *mut c_char;
 
     pub fn stbi_zlib_decode_buffer(
@@ -166,7 +166,7 @@ extern "C" {
     pub fn stbi_zlib_decode_noheader_malloc(
         buffer: *const c_char,
         len: c_int,
-        outlen: *mut c_int,
+        outlen: &mut c_int,
     ) -> *mut c_char;
 
     pub fn stbi_zlib_decode_noheader_buffer(
index cd14ed5deff2d3fd8d55c5b0e346d41b600d0c1c..bc3c075dc409cfe431977211d693291b287d8d60 100644 (file)
@@ -5,4 +5,5 @@ edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
-[dependencies]
\ No newline at end of file
+[dependencies]
+stb_image-sys = { path = "../ffi/stb_image-sys" }
\ No newline at end of file
diff --git a/narcissus-core/src/image.rs b/narcissus-core/src/image.rs
new file mode 100644 (file)
index 0000000..cd16d36
--- /dev/null
@@ -0,0 +1,103 @@
+use std::ptr::NonNull;
+
+use stb_image_sys::{stbi_image_free, stbi_load_from_memory};
+
+#[derive(Debug)]
+pub struct LoadError;
+
+impl std::fmt::Display for LoadError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("LoadError").finish()
+    }
+}
+
+impl std::error::Error for LoadError {}
+
+pub struct Image {
+    width: usize,
+    height: usize,
+    components: usize,
+    len: usize,
+    buffer: NonNull<u8>,
+}
+
+impl Image {
+    pub fn from_buffer(buffer: &[u8]) -> Result<Image, LoadError> {
+        let mut x = 0;
+        let mut y = 0;
+        let mut components = 0;
+        let required_components = 0;
+        let buffer = unsafe {
+            stbi_load_from_memory(
+                buffer.as_ptr(),
+                buffer.len() as i32,
+                &mut x,
+                &mut y,
+                &mut components,
+                required_components,
+            )
+        };
+
+        if buffer.is_null() {
+            return Err(LoadError);
+        }
+
+        let x = x as usize;
+        let y = y as usize;
+        let components = components as usize;
+        let len = x * y * components;
+
+        Ok(Image {
+            width: x,
+            height: y,
+            components,
+            len,
+            // Safety: We just checked that buffer is not null above.
+            buffer: unsafe { NonNull::new_unchecked(buffer) },
+        })
+    }
+
+    /// Returns the image's width in pixels.
+    #[inline]
+    pub fn width(&self) -> usize {
+        self.width
+    }
+
+    /// Returns the image's height in pixels.
+    #[inline]
+    pub fn height(&self) -> usize {
+        self.height
+    }
+
+    /// Returns the number of components in this image.
+    #[inline]
+    pub fn components(&self) -> usize {
+        self.components
+    }
+
+    /// The pixel data consists of [`height()`] scanlines of [`width()`] pixels,
+    /// with each pixel consisting of [`components()`] interleaved 8-bit components; the first
+    /// pixel pointed to is top-left-most in the image. There is no padding between
+    /// image scanlines or between pixels, regardless of format.
+    ///
+    /// An output image with N components has the following components interleaved
+    /// in this order in each pixel:
+    ///
+    /// |  N |   Components            |
+    /// |----|-------------------------|
+    /// | 1  | grey                    |
+    /// | 2  | grey, alpha             |
+    /// | 3  | red, green, blue        |
+    /// | 4  | red, green, blue, alpha |
+    pub fn as_slice(&self) -> &[u8] {
+        // Safety: Slice size is calculated when creating `Image`.
+        unsafe { std::slice::from_raw_parts(self.buffer.as_ptr(), self.len) }
+    }
+}
+
+impl Drop for Image {
+    fn drop(&mut self) {
+        // Safety: Always allocated by `stbi_load_xxx` functions.
+        unsafe { stbi_image_free(self.buffer.as_ptr() as *mut _) }
+    }
+}
index c20a0afdf0301b158d5a2b264c4abfa9cf1abde0..e0fef028809f6dd0dde22dce2c33e8fd263dcd05 100644 (file)
@@ -1,5 +1,6 @@
 mod bitset;
 mod fixed_vec;
+mod image;
 mod libc;
 pub mod manual_arc;
 mod mutex;
@@ -12,6 +13,7 @@ mod waiter;
 
 pub use bitset::BitIter;
 pub use fixed_vec::FixedVec;
+pub use image::Image;
 pub use mutex::Mutex;
 pub use pool::{Handle, Pool};
 pub use ref_count::{Arc, Rc};