ivy_image/
image.rs

1use crate::{Error, Result};
2use libc::*;
3use std::path::Path;
4
5#[link(name = "stb")]
6extern "C" {
7    fn stbi_load(
8        filename: *const c_char,
9        x: *mut c_int,
10        y: *mut c_int,
11        channels: *mut c_int,
12        desired_channels: c_int,
13    ) -> *mut c_uchar;
14
15    fn stbi_load_from_memory(
16        buf: *const c_uchar,
17        len: c_int,
18        x: *mut c_int,
19        y: *mut c_int,
20        channels: *mut c_int,
21        desired_channels: c_int,
22    ) -> *mut c_uchar;
23}
24
25pub struct Image {
26    width: u32,
27    height: u32,
28    channels: u32,
29    pixels: Box<[u8]>,
30}
31
32impl Image {
33    pub fn new(width: u32, height: u32, channels: u32, pixels: Box<[u8]>) -> Self {
34        Self {
35            width: width as _,
36            height: height as _,
37            channels: channels as _,
38            pixels,
39        }
40    }
41
42    /// Loads an image from a path
43    pub fn load<P: AsRef<Path>>(path: P, desired_channels: i32) -> Result<Self> {
44        let filename = std::ffi::CString::new(path.as_ref().as_os_str().to_str().unwrap())
45            .ok()
46            .unwrap();
47
48        let mut width: c_int = 0;
49        let mut height: c_int = 0;
50        let mut channels: c_int = desired_channels;
51
52        let pixels_raw = unsafe {
53            stbi_load(
54                filename.as_ptr(),
55                &mut width,
56                &mut height,
57                &mut channels,
58                desired_channels,
59            )
60        };
61
62        if pixels_raw.is_null() {
63            return Err(Error::FileLoading(path.as_ref().to_owned()));
64        }
65
66        // Desired channels override channels
67        if desired_channels != 0 {
68            channels = desired_channels;
69        }
70
71        let image_size = width as usize * height as usize * channels as usize;
72        let pixels = unsafe { Vec::from_raw_parts(pixels_raw, image_size, image_size) };
73        let pixels = pixels.into_boxed_slice();
74
75        Ok(Image::new(width as _, height as _, channels as _, pixels))
76    }
77
78    /// Loads an image from memory, such as a memory mapped file
79    pub fn load_from_memory(buf: &[u8], desired_channels: i32) -> Result<Self> {
80        let mut width: c_int = 0;
81        let mut height: c_int = 0;
82        let mut channels: c_int = desired_channels;
83        // let desired_channels: c_int = 0;
84
85        let pixels_raw = unsafe {
86            stbi_load_from_memory(
87                buf.as_ptr(),
88                buf.len() as i32,
89                &mut width,
90                &mut height,
91                &mut channels,
92                desired_channels,
93            )
94        };
95
96        if pixels_raw.is_null() {
97            return Err(Error::MemoryLoading);
98        }
99
100        // Desired channels override channels
101        if desired_channels != 0 {
102            channels = desired_channels;
103        }
104
105        let image_size = width as usize * height as usize * channels as usize;
106        let pixels = unsafe { Vec::from_raw_parts(pixels_raw, image_size, image_size) };
107        let pixels = pixels.into_boxed_slice();
108
109        Ok(Image::new(width as _, height as _, channels as _, pixels))
110    }
111
112    pub fn width(&self) -> u32 {
113        self.width
114    }
115
116    pub fn height(&self) -> u32 {
117        self.height
118    }
119
120    pub fn channels(&self) -> u32 {
121        self.channels
122    }
123
124    pub fn pixels(&self) -> &[u8] {
125        &self.pixels
126    }
127
128    pub fn pixels_mut(&mut self) -> &mut [u8] {
129        &mut self.pixels
130    }
131}