use super::{
InsufficientBuffer, MixedSinker, MixedSinkerError, RowIndexOutOfRange, RowShapeMismatch,
RowSlice, check_dimensions_match, rgb_row_buf_or_scratch, rgba_plane_row_slice,
rgba_u16_plane_row_slice,
};
use crate::{
PixelSink,
row::{
rgb_to_hsv_row, xyz12_rgb_to_luma_row, xyz12_rgb_to_luma_u16_row, xyz12_to_rgb_f16_row,
xyz12_to_rgb_f32_row, xyz12_to_rgb_row, xyz12_to_rgb_u16_row, xyz12_to_rgba_f16_row,
xyz12_to_rgba_row, xyz12_to_rgba_u16_row, xyz12_to_xyz_f32_row,
},
source::{Xyz12, Xyz12Row, Xyz12Sink},
};
impl<'a, const BE: bool> MixedSinker<'a, Xyz12<BE>> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_rgba(mut self, buf: &'a mut [u8]) -> Result<Self, MixedSinkerError> {
self.set_rgba(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_rgba(&mut self, buf: &'a mut [u8]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_elems(4)?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientRgbaBuffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.rgba = Some(buf);
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_rgb_u16(mut self, buf: &'a mut [u16]) -> Result<Self, MixedSinkerError> {
self.set_rgb_u16(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_rgb_u16(&mut self, buf: &'a mut [u16]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_elems(3)?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientRgbU16Buffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.rgb_u16 = Some(buf);
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_rgba_u16(mut self, buf: &'a mut [u16]) -> Result<Self, MixedSinkerError> {
self.set_rgba_u16(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_rgba_u16(&mut self, buf: &'a mut [u16]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_elems(4)?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientRgbaU16Buffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.rgba_u16 = Some(buf);
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_luma_u16(mut self, buf: &'a mut [u16]) -> Result<Self, MixedSinkerError> {
self.set_luma_u16(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_luma_u16(&mut self, buf: &'a mut [u16]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_pixels()?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientLumaU16Buffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.luma_u16 = Some(buf);
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_rgb_f32(mut self, buf: &'a mut [f32]) -> Result<Self, MixedSinkerError> {
self.set_rgb_f32(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_rgb_f32(&mut self, buf: &'a mut [f32]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_elems(3)?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientRgbF32Buffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.rgb_f32 = Some(buf);
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_xyz_f32(mut self, buf: &'a mut [f32]) -> Result<Self, MixedSinkerError> {
self.set_xyz_f32(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_xyz_f32(&mut self, buf: &'a mut [f32]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_elems(3)?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientXyzF32Buffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.xyz_f32 = Some(buf);
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_rgb_f16(mut self, buf: &'a mut [half::f16]) -> Result<Self, MixedSinkerError> {
self.set_rgb_f16(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_rgb_f16(&mut self, buf: &'a mut [half::f16]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_elems(3)?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientRgbF16Buffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.rgb_f16 = Some(buf);
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_rgba_f16(mut self, buf: &'a mut [half::f16]) -> Result<Self, MixedSinkerError> {
self.set_rgba_f16(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_rgba_f16(&mut self, buf: &'a mut [half::f16]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_elems(4)?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientRgbaF16Buffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.rgba_f16 = Some(buf);
Ok(self)
}
}
impl<const BE: bool> Xyz12Sink<BE> for MixedSinker<'_, Xyz12<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, Xyz12<BE>> {
type Input<'r> = Xyz12Row<'r, BE>;
type Error = MixedSinkerError;
fn begin_frame(&mut self, width: u32, height: u32) -> Result<(), Self::Error> {
check_dimensions_match(self.width, self.height, width, height)
}
fn process(&mut self, row: Xyz12Row<'_, BE>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
let target_gamut = row.target_gamut();
if row.xyz().len() != w * 3 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Xyz12Packed,
idx,
w * 3,
row.xyz().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgb_u16,
rgb_f32,
rgb_f16,
rgba,
rgba_u16,
rgba_f16,
luma,
luma_u16,
hsv,
xyz_f32,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let xyz_in = row.xyz();
if let Some(buf) = xyz_f32.as_deref_mut() {
let f32_start = one_plane_start * 3;
let f32_end = one_plane_end * 3;
xyz12_to_xyz_f32_row::<BE>(xyz_in, &mut buf[f32_start..f32_end], w, use_simd);
}
if let Some(buf) = rgb_f32.as_deref_mut() {
let f32_start = one_plane_start * 3;
let f32_end = one_plane_end * 3;
xyz12_to_rgb_f32_row::<BE>(
xyz_in,
&mut buf[f32_start..f32_end],
w,
target_gamut,
use_simd,
);
}
if let Some(buf) = rgb_f16.as_deref_mut() {
let f16_start = one_plane_start * 3;
let f16_end = one_plane_end * 3;
xyz12_to_rgb_f16_row::<BE>(
xyz_in,
&mut buf[f16_start..f16_end],
w,
target_gamut,
use_simd,
);
}
if let Some(buf) = rgba_f16.as_deref_mut() {
let f16_start = one_plane_start * 4;
let f16_end = one_plane_end * 4;
xyz12_to_rgba_f16_row::<BE>(
xyz_in,
&mut buf[f16_start..f16_end],
w,
target_gamut,
use_simd,
);
}
if let Some(buf) = rgb_u16.as_deref_mut() {
let u16_start = one_plane_start * 3;
let u16_end = one_plane_end * 3;
xyz12_to_rgb_u16_row::<BE>(
xyz_in,
&mut buf[u16_start..u16_end],
w,
target_gamut,
use_simd,
);
}
if let Some(buf) = rgba_u16.as_deref_mut() {
let rgba_row = rgba_u16_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
xyz12_to_rgba_u16_row::<BE>(xyz_in, rgba_row, w, target_gamut, use_simd);
}
let want_rgba_u8 = rgba.is_some();
let want_rgb_u8 = rgb.is_some();
let want_luma_u8 = luma.is_some();
let want_luma_u16 = luma_u16.is_some();
let want_hsv = hsv.is_some();
let need_u8_rgb = want_rgb_u8 || want_luma_u8 || want_luma_u16 || want_hsv;
if want_rgba_u8 && !need_u8_rgb {
let rgba_buf = rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?;
xyz12_to_rgba_row::<BE>(xyz_in, rgba_row, w, target_gamut, use_simd);
return Ok(());
}
if !need_u8_rgb && !want_rgba_u8 {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
xyz12_to_rgb_row::<BE>(xyz_in, rgb_row, w, target_gamut, use_simd);
if let Some(luma) = luma.as_deref_mut() {
xyz12_rgb_to_luma_row(
rgb_row,
&mut luma[one_plane_start..one_plane_end],
w,
row.luma_q15(),
use_simd,
);
}
if let Some(luma_buf) = luma_u16.as_deref_mut() {
xyz12_rgb_to_luma_u16_row(
rgb_row,
&mut luma_buf[one_plane_start..one_plane_end],
w,
row.luma_q15(),
use_simd,
);
}
if let Some(hsv) = hsv.as_mut() {
let (h, s, v) = hsv.hsv();
rgb_to_hsv_row(
rgb_row,
&mut h[one_plane_start..one_plane_end],
&mut s[one_plane_start..one_plane_end],
&mut v[one_plane_start..one_plane_end],
w,
use_simd,
);
}
if let Some(buf) = rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
xyz12_to_rgba_row::<BE>(xyz_in, rgba_row, w, target_gamut, use_simd);
}
Ok(())
}
}