use stb_sys as sys;
use std::ffi::c_void;
use std::ffi::CStr;
use std::os::raw;
use std::slice;
pub fn stbi_write_png(
filename: &CStr,
w: i32,
h: i32,
comp: i32,
buffer: &[u8],
stride_in_bytes: i32,
) -> Option<()> {
let ret = unsafe {
sys::stbi_write_png(
filename.as_ptr() as *mut i8,
w,
h,
comp,
buffer.as_ptr() as *const c_void,
stride_in_bytes,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
pub fn stbi_write_bmp(filename: &CStr, w: i32, h: i32, comp: i32, buffer: &[u8]) -> Option<()> {
let ret = unsafe {
sys::stbi_write_bmp(
filename.as_ptr() as *mut i8,
w,
h,
comp,
buffer.as_ptr() as *const c_void,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
pub fn stbi_write_tga(filename: &CStr, w: i32, h: i32, comp: i32, buffer: &[u8]) -> Option<()> {
let ret = unsafe {
sys::stbi_write_tga(
filename.as_ptr() as *mut i8,
w,
h,
comp,
buffer.as_ptr() as *const c_void,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
pub fn stbi_write_hdr(filename: &CStr, w: i32, h: i32, comp: i32, buffer: &[f32]) -> Option<()> {
let ret =
unsafe { sys::stbi_write_hdr(filename.as_ptr() as *mut i8, w, h, comp, buffer.as_ptr()) };
if ret == 0 {
None
} else {
Some(())
}
}
pub fn stbi_write_jpg(
filename: &CStr,
w: i32,
h: i32,
comp: i32,
buffer: &[u8],
quality: i32,
) -> Option<()> {
let ret = unsafe {
sys::stbi_write_jpg(
filename.as_ptr() as *mut i8,
w,
h,
comp,
buffer.as_ptr() as *const c_void,
quality,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
extern "C" fn write_func<F, T>(context: *mut raw::c_void, data: *mut raw::c_void, size: raw::c_int)
where
F: FnMut(&[T]),
{
let buffer = unsafe { slice::from_raw_parts_mut(data as *mut T, size as _) };
let f: &mut F = unsafe { &mut *(context as *mut F) };
f(buffer)
}
pub fn stbi_write_png_to_func<F>(
func: &mut F,
w: i32,
h: i32,
comp: i32,
buffer: &[u8],
stride_in_bytes: i32,
) -> Option<()>
where
F: FnMut(&[u8]),
{
let ret = unsafe {
sys::stbi_write_png_to_func(
Some(write_func::<F, u8>),
func as *mut F as *mut c_void,
w,
h,
comp,
buffer.as_ptr() as *const c_void,
stride_in_bytes,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
pub fn stbi_write_bmp_to_func<F>(
func: &mut F,
w: i32,
h: i32,
comp: i32,
buffer: &[u8],
) -> Option<()>
where
F: FnMut(&[u8]),
{
let ret = unsafe {
sys::stbi_write_bmp_to_func(
Some(write_func::<F, u8>),
func as *mut F as *mut c_void,
w,
h,
comp,
buffer.as_ptr() as *const c_void,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
pub fn stbi_write_tga_to_func<F>(
func: &mut F,
w: i32,
h: i32,
comp: i32,
buffer: &[u8],
) -> Option<()>
where
F: FnMut(&[u8]),
{
let ret = unsafe {
sys::stbi_write_tga_to_func(
Some(write_func::<F, u8>),
func as *mut F as *mut c_void,
w,
h,
comp,
buffer.as_ptr() as *const c_void,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
pub fn stbi_write_hdr_to_func<F>(
func: &mut F,
w: i32,
h: i32,
comp: i32,
buffer: &[f32],
) -> Option<()>
where
F: FnMut(&[f32]),
{
let ret = unsafe {
sys::stbi_write_hdr_to_func(
Some(write_func::<F, f32>),
func as *mut F as *mut c_void,
w,
h,
comp,
buffer.as_ptr() as *const f32,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
pub fn stbi_write_jpg_to_func<F>(
func: &mut F,
w: i32,
h: i32,
comp: i32,
buffer: &[u8],
quality: i32,
) -> Option<()>
where
F: FnMut(&[u8]),
{
let ret = unsafe {
sys::stbi_write_jpg_to_func(
Some(write_func::<F, u8>),
func as *mut F as *mut c_void,
w,
h,
comp,
buffer.as_ptr() as *const c_void,
quality,
)
};
if ret == 0 {
None
} else {
Some(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::CString;
use std::fs;
#[test]
fn write_bmp() {
let mut dir = std::env::temp_dir();
dir.push("test.bmp");
let str = dir.to_str().unwrap();
let path = CString::new(str).unwrap();
stbi_write_bmp(&path, 1, 1, 1, &[1]).expect("Failed to write BMP");
fs::metadata(str).expect("Failed to check whether BMP file exists");
fs::remove_file(str).expect("Failed to remove BMP file");
}
#[test]
fn write_bmp_callback() {
let mut counter = 0;
stbi_write_bmp_to_func(
&mut |_data| {
counter += 1;
},
1,
1,
1,
&[1],
)
.expect("Failed to write BMP to func");
assert_ne!(counter, 0);
}
}