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;
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;
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);
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(
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(
--- /dev/null
+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 _) }
+ }
+}