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 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 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 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 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 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}