use crate::{
core::{error::Error, frame_buffer::FrameBuffer},
deep::{
deep_scan_line_input_file::DeepScanLineInputFile,
deep_scan_line_input_part::DeepScanLineInputPart,
},
};
use imath_traits::Bound2;
use openexr_sys as sys;
type Result<T, E = Error> = std::result::Result<T, E>;
pub struct CompositeDeepScanLine<'a, 'p> {
pub(crate) ptr: *mut sys::Imf_CompositeDeepScanLine_t,
parts: Vec<&'a DeepScanLineInputPart<'p>>,
files: Vec<&'a DeepScanLineInputFile>,
frame_buffer: Option<&'a FrameBuffer>,
}
impl<'a, 'p> CompositeDeepScanLine<'a, 'p> {
pub fn new() -> CompositeDeepScanLine<'a, 'p> {
CompositeDeepScanLine::default()
}
pub fn add_source_part(
&mut self,
part: &'a mut DeepScanLineInputPart<'p>,
) -> Result<()> {
unsafe {
sys::Imf_CompositeDeepScanLine_addSource_part(
self.ptr,
&mut part.inner,
)
.into_result()?;
}
self.parts.push(part);
Ok(())
}
pub fn add_source_file(
&mut self,
file: &'a DeepScanLineInputFile,
) -> Result<()> {
unsafe {
sys::Imf_CompositeDeepScanLine_addSource_file(self.ptr, file.0)
.into_result()?;
}
self.files.push(file);
Ok(())
}
pub fn set_frame_buffer(&mut self, frame_buffer: &'a FrameBuffer) {
unsafe {
sys::Imf_CompositeDeepScanLine_setFrameBuffer(
self.ptr,
frame_buffer.ptr,
)
.into_result()
.unwrap();
}
self.frame_buffer = Some(frame_buffer);
}
pub fn frame_buffer(&self) -> Option<&'a FrameBuffer> {
self.frame_buffer
}
pub fn read_pixels(&mut self, start: i32, end: i32) -> Result<()> {
let dw = *self.data_window::<[i32; 4]>();
if start < dw[1] || end > dw[3] {
Err(Error::OutOfRange)
} else {
unsafe {
sys::Imf_CompositeDeepScanLine_readPixels(self.ptr, start, end)
.into_result()?;
}
Ok(())
}
}
pub fn num_sources(&self) -> i32 {
let mut num = 0;
unsafe {
sys::Imf_CompositeDeepScanLine_sources(self.ptr, &mut num)
.into_result()
.unwrap();
}
num
}
pub fn data_window<B>(&self) -> &B
where
B: Bound2<i32>,
{
let mut ptr = std::ptr::null();
unsafe {
sys::Imf_CompositeDeepScanLine_dataWindow(self.ptr, &mut ptr);
&*(ptr as *const B)
}
}
}
impl<'a, 'p> Default for CompositeDeepScanLine<'a, 'p> {
fn default() -> CompositeDeepScanLine<'a, 'p> {
unsafe {
let mut ptr = std::ptr::null_mut();
sys::Imf_CompositeDeepScanLine_ctor(&mut ptr);
CompositeDeepScanLine {
ptr,
parts: Vec::new(),
files: Vec::new(),
frame_buffer: None,
}
}
}
}
#[cfg(test)]
#[test]
fn composite_deep1() -> Result<()> {
use crate::{
core::{
channel_list::{CHANNEL_FLOAT, CHANNEL_HALF},
frame_buffer::Frame,
header::Header,
output_file::OutputFile,
},
rgba::rgba::Rgba,
};
use std::path::PathBuf;
let path_plane = PathBuf::from(
std::env::var("CARGO_MANIFEST_DIR")
.expect("CARGO_MANIFEST_DIR not set"),
)
.join("images")
.join("deep_plane.exr");
let path_cyl = PathBuf::from(
std::env::var("CARGO_MANIFEST_DIR")
.expect("CARGO_MANIFEST_DIR not set"),
)
.join("images")
.join("deep_cyl.exr");
let file_plane = DeepScanLineInputFile::new(&path_plane, 4)?;
let header_plane = file_plane.header();
let data_window_plane = *header_plane.data_window::<[i32; 4]>();
let file_cyl = DeepScanLineInputFile::new(&path_cyl, 4)?;
let header_cyl = file_cyl.header();
let data_window_cyl = *header_cyl.data_window::<[i32; 4]>();
let data_window = [
data_window_plane[0].min(data_window_cyl[0]),
data_window_plane[1].min(data_window_cyl[1]),
data_window_plane[2].max(data_window_cyl[2]),
data_window_plane[3].max(data_window_cyl[3]),
];
let mut frame_buffer = FrameBuffer::new();
frame_buffer.insert_frame(Frame::new::<Rgba, _, _>(
&["R", "G", "B", "A"],
data_window,
)?)?;
frame_buffer.insert_frame(Frame::new::<f32, _, _>(&["Z"], data_window)?)?;
let mut cds = CompositeDeepScanLine::new();
cds.add_source_file(&file_plane)?;
cds.add_source_file(&file_cyl)?;
cds.set_frame_buffer(&frame_buffer);
cds.read_pixels(data_window[1], data_window[3])?;
let mut header = Header::new(
data_window,
*header_plane.display_window(),
1.0,
[0.0f32; 2],
1.0,
sys::LineOrder::IncreasingY,
sys::Compression::Zips,
)?;
for c in &["R", "G", "B", "A"] {
header.channels_mut().insert(c, &CHANNEL_HALF);
}
header.channels_mut().insert("Z", &CHANNEL_FLOAT);
let mut file = OutputFile::new("composite_deep1.exr", &header, 6).unwrap();
file.set_frame_buffer(&frame_buffer).unwrap();
unsafe {
file.write_pixels(data_window[3] - data_window[1] + 1)
.unwrap()
};
Ok(())
}