use openexr_sys as sys;
use std::ffi::CString;
use std::path::Path;
use crate::core::{
error::Error,
header::{HeaderRef, HeaderSlice},
};
type Result<T, E = Error> = std::result::Result<T, E>;
#[repr(transparent)]
pub struct MultiPartOutputFile(pub(crate) *mut sys::Imf_MultiPartOutputFile_t);
impl MultiPartOutputFile {
pub fn new<P: AsRef<Path>>(
filename: P,
headers: &HeaderSlice,
override_shared_attributes: bool,
num_threads: i32,
) -> Result<MultiPartOutputFile> {
let c_filename = CString::new(
filename
.as_ref()
.to_str()
.expect("Invalid bytes in filename"),
)
.expect("Internal null bytes in filename");
let mut ptr = std::ptr::null_mut();
unsafe {
sys::Imf_MultiPartOutputFile_ctor(
&mut ptr,
c_filename.as_ptr(),
headers.0.as_ptr(),
headers.0.len() as i32,
override_shared_attributes,
num_threads,
)
.into_result()?;
}
Ok(MultiPartOutputFile(ptr))
}
pub fn parts(&self) -> i32 {
let mut v = 0;
unsafe {
sys::Imf_MultiPartOutputFile_parts(self.0, &mut v);
}
v
}
pub fn header(&self, n: i32) -> Result<HeaderRef> {
let mut ptr = std::ptr::null();
unsafe {
sys::Imf_MultiPartOutputFile_header(self.0, &mut ptr, n)
.into_result()?;
}
Ok(HeaderRef::new(ptr))
}
}
impl Drop for MultiPartOutputFile {
fn drop(&mut self) {
unsafe {
sys::Imf_MultiPartOutputFile_dtor(self.0);
}
}
}
#[cfg(test)]
#[test]
fn write_multipartoutputfile1() {
use crate::{
core::{
channel_list::Channel,
frame_buffer::{FrameBuffer, Slice},
header::{Header, ImageType},
output_part::OutputPart,
Compression, PixelType,
},
rgba::rgba::Rgba,
};
let (pixels, width, height) = crate::tests::load_ferris();
let channel = Channel {
type_: PixelType::Half.into(),
x_sampling: 1,
y_sampling: 1,
p_linear: true,
};
let mut header_array = Header::new_array(2);
let mut i = 0;
for mut header in header_array.iter_mut() {
header.set_compression(Compression::Zip);
header.channels_mut().insert("R", &channel);
header.channels_mut().insert("G", &channel);
header.channels_mut().insert("B", &channel);
header.channels_mut().insert("A", &channel);
header.set_image_type(ImageType::Scanline);
header.set_dimensions(width, height);
if i == 0 {
header.set_name("left");
i += 1;
} else {
header.set_name("right");
}
}
let mut frame_buffer_left = FrameBuffer::new();
frame_buffer_left
.insert(
"R",
&Slice::builder(
PixelType::Half,
&pixels[0].r as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Rgba>())
.build()
.unwrap(),
)
.unwrap();
frame_buffer_left
.insert(
"G",
&Slice::builder(
PixelType::Half,
&pixels[0].g as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Rgba>())
.build()
.unwrap(),
)
.unwrap();
frame_buffer_left
.insert(
"B",
&Slice::builder(
PixelType::Half,
&pixels[0].b as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Rgba>())
.build()
.unwrap(),
)
.unwrap();
frame_buffer_left
.insert(
"A",
&Slice::builder(
PixelType::Half,
&pixels[0].a as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Rgba>())
.build()
.unwrap(),
)
.unwrap();
let mut frame_buffer_right = FrameBuffer::new();
frame_buffer_right
.insert(
"B",
&Slice::builder(
PixelType::Half,
&pixels[0].r as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Rgba>())
.build()
.unwrap(),
)
.unwrap();
frame_buffer_right
.insert(
"G",
&Slice::builder(
PixelType::Half,
&pixels[0].g as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Rgba>())
.build()
.unwrap(),
)
.unwrap();
frame_buffer_right
.insert(
"R",
&Slice::builder(
PixelType::Half,
&pixels[0].b as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Rgba>())
.build()
.unwrap(),
)
.unwrap();
frame_buffer_right
.insert(
"A",
&Slice::builder(
PixelType::Half,
&pixels[0].a as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Rgba>())
.build()
.unwrap(),
)
.unwrap();
let file = MultiPartOutputFile::new(
"write_multipartoutputfile1.exr",
&header_array,
true,
4,
)
.unwrap();
let mut part_left = OutputPart::new(&file, 0).unwrap();
let mut part_right = OutputPart::new(&file, 1).unwrap();
part_left.set_frame_buffer(&frame_buffer_left).unwrap();
part_right.set_frame_buffer(&frame_buffer_right).unwrap();
unsafe {
part_left.write_pixels(height).unwrap();
part_right.write_pixels(height).unwrap();
}
}