use super::{
GeometryOverflow, 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::{
expand_rgb_to_rgba_row, expand_rgb_u16_to_rgba_u16_row, gray_n_to_hsv_row, gray_n_to_luma_row,
gray_n_to_luma_u16_row, gray_n_to_rgb_row, gray_n_to_rgb_u16_row, gray_n_to_rgba_row,
gray_n_to_rgba_u16_row, gray8_to_hsv_row, gray8_to_rgb_row, gray8_to_rgba_row,
gray16_to_hsv_row, gray16_to_luma_row, gray16_to_luma_u16_row, gray16_to_rgb_row,
gray16_to_rgb_u16_row, gray16_to_rgba_row, gray16_to_rgba_u16_row, grayf32_to_hsv_row,
grayf32_to_luma_f32_row, grayf32_to_luma_row, grayf32_to_luma_u16_row, grayf32_to_rgb_f32_row,
grayf32_to_rgb_row, grayf32_to_rgb_u16_row, grayf32_to_rgba_row, grayf32_to_rgba_u16_row,
rgb_to_hsv_row,
scalar::alpha_extract::{copy_alpha_ya_u8, copy_alpha_ya_u16, copy_alpha_ya_u16_to_u8},
y_plane_to_luma_u16_row, ya8_to_hsv_row, ya8_to_luma_row, ya8_to_luma_u16_row, ya8_to_rgb_row,
ya8_to_rgb_u16_row, ya8_to_rgba_row, ya8_to_rgba_u16_row, ya16_to_hsv_row, ya16_to_luma_row,
ya16_to_luma_u16_row, ya16_to_rgb_row, ya16_to_rgb_u16_row, ya16_to_rgba_row,
ya16_to_rgba_u16_row,
},
source::{
Gray8, Gray8Row, Gray8Sink, Gray16, Gray16Row, Gray16Sink, Grayf32, Grayf32Row, Grayf32Sink,
Ya8, Ya8Row, Ya8Sink, Ya16, Ya16Row, Ya16Sink,
},
};
impl<'a> MixedSinker<'a, Gray8> {
#[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_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)
}
}
impl Gray8Sink for MixedSinker<'_, Gray8> {}
impl PixelSink for MixedSinker<'_, Gray8> {
type Input<'r> = Gray8Row<'r>;
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: Gray8Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.y().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Y,
idx,
w,
row.y().len(),
)));
}
if idx >= h {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, h),
));
}
let Self {
rgb,
rgba,
luma,
luma_u16,
hsv,
rgb_scratch,
..
} = self;
let y_plane = row.y();
let full_range = row.full_range();
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
if let Some(buf) = luma.as_deref_mut() {
buf[one_plane_start..one_plane_end].copy_from_slice(y_plane);
}
if let Some(buf) = luma_u16.as_deref_mut() {
y_plane_to_luma_u16_row(
y_plane,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
let want_rgb = rgb.is_some();
let want_rgba = rgba.is_some();
let want_hsv = hsv.is_some();
if want_rgba && !want_rgb && !want_hsv {
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)?;
gray8_to_rgba_row(y_plane, rgba_row, w, use_simd, full_range);
return Ok(());
}
if want_hsv && !want_rgb && !want_rgba {
let hsv = hsv.as_mut().unwrap();
let (h, s, v) = hsv.hsv();
gray8_to_hsv_row(
y_plane,
&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,
full_range,
);
return Ok(());
}
if !want_rgb && !want_rgba && !want_hsv {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
gray8_to_rgb_row(y_plane, rgb_row, w, use_simd, full_range);
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)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
}
Ok(())
}
}
#[allow(clippy::too_many_arguments)]
#[inline(always)]
fn process_gray_n<'a, const BITS: u32, const BE: bool>(
w: usize,
h: usize,
idx: usize,
use_simd: bool,
full_range: bool,
y_plane: &[u16],
rgb: &mut Option<&'a mut [u8]>,
rgb_u16: &mut Option<&'a mut [u16]>,
rgba: &mut Option<&'a mut [u8]>,
rgba_u16: &mut Option<&'a mut [u16]>,
luma: &mut Option<&'a mut [u8]>,
luma_u16: &mut Option<&'a mut [u16]>,
hsv: &mut Option<mediaframe::source::HsvFrameMut<'a>>,
rgb_scratch: &mut std::vec::Vec<u8>,
) -> Result<(), MixedSinkerError> {
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
if let Some(buf) = luma.as_deref_mut() {
gray_n_to_luma_row::<BITS, BE>(
y_plane,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
if let Some(buf) = luma_u16.as_deref_mut() {
gray_n_to_luma_u16_row::<BITS, BE>(
y_plane,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
let want_rgb_u16 = rgb_u16.is_some();
let want_rgba_u16 = rgba_u16.is_some();
if want_rgba_u16 && !want_rgb_u16 {
let rgba_u16_buf = rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row =
rgba_u16_plane_row_slice(rgba_u16_buf, one_plane_start, one_plane_end, w, h)?;
gray_n_to_rgba_u16_row::<BITS, BE>(y_plane, rgba_u16_row, w, use_simd, full_range);
} else if want_rgb_u16 {
let rgb_u16_buf = rgb_u16.as_deref_mut().unwrap();
let rgb_plane_start = one_plane_start * 3;
let rgb_plane_end = one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
let rgb_u16_row = &mut rgb_u16_buf[rgb_plane_start..rgb_plane_end];
gray_n_to_rgb_u16_row::<BITS, BE>(y_plane, rgb_u16_row, w, use_simd, full_range);
if want_rgba_u16 {
let rgba_u16_buf = rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row =
rgba_u16_plane_row_slice(rgba_u16_buf, one_plane_start, one_plane_end, w, h)?;
expand_rgb_u16_to_rgba_u16_row::<BITS>(rgb_u16_row, rgba_u16_row, w);
}
}
let want_rgb = rgb.is_some();
let want_rgba = rgba.is_some();
let want_hsv = hsv.is_some();
if want_rgba && !want_rgb && !want_hsv {
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)?;
gray_n_to_rgba_row::<BITS, BE>(y_plane, rgba_row, w, use_simd, full_range);
return Ok(());
}
if want_hsv && !want_rgb && !want_rgba {
let hsv = hsv.as_mut().unwrap();
let (h, s, v) = hsv.hsv();
gray_n_to_hsv_row::<BITS, BE>(
y_plane,
&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,
full_range,
);
return Ok(());
}
if !want_rgb && !want_rgba && !want_hsv {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
gray_n_to_rgb_row::<BITS, BE>(y_plane, rgb_row, w, use_simd, full_range);
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)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
}
Ok(())
}
#[inline(always)]
fn check_gray_n_row_shape(
y_len: usize,
w: usize,
idx: usize,
h: usize,
) -> Result<(), MixedSinkerError> {
if y_len != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Y,
idx,
w,
y_len,
)));
}
if idx >= h {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, h),
));
}
Ok(())
}
macro_rules! impl_gray_n_sinker {
($marker:ident, $row:ident, $sink:ident, $bits:expr) => {
impl<'a, const BE: bool> MixedSinker<'a, $marker<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)
}
}
impl<const BE: bool> $sink<BE> for MixedSinker<'_, $marker<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, $marker<BE>> {
type Input<'r> = $row<'r>;
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: $row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let use_simd = self.simd;
let idx = row.row();
let full_range = row.full_range();
check_gray_n_row_shape(row.y().len(), w, idx, h)?;
let y_plane = row.y();
let Self {
rgb,
rgb_u16,
rgba,
rgba_u16,
luma,
luma_u16,
hsv,
rgb_scratch,
..
} = self;
process_gray_n::<$bits, BE>(
w,
h,
idx,
use_simd,
full_range,
y_plane,
rgb,
rgb_u16,
rgba,
rgba_u16,
luma,
luma_u16,
hsv,
rgb_scratch,
)
}
}
};
}
use crate::source::{
Gray9, Gray9Row, Gray9Sink, Gray10, Gray10Row, Gray10Sink, Gray12, Gray12Row, Gray12Sink, Gray14,
Gray14Row, Gray14Sink,
};
impl_gray_n_sinker!(Gray9, Gray9Row, Gray9Sink, 9);
impl_gray_n_sinker!(Gray10, Gray10Row, Gray10Sink, 10);
impl_gray_n_sinker!(Gray12, Gray12Row, Gray12Sink, 12);
impl_gray_n_sinker!(Gray14, Gray14Row, Gray14Sink, 14);
impl<'a, const BE: bool> MixedSinker<'a, Gray16<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)
}
}
impl<const BE: bool> Gray16Sink<BE> for MixedSinker<'_, Gray16<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, Gray16<BE>> {
type Input<'r> = Gray16Row<'r>;
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: Gray16Row<'_>) -> Result<(), Self::Error> {
const BITS: u32 = 16;
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
let full_range = row.full_range();
if row.y().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Y,
idx,
w,
row.y().len(),
)));
}
if idx >= h {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, h),
));
}
let Self {
rgb,
rgb_u16,
rgba,
rgba_u16,
luma,
luma_u16,
hsv,
rgb_scratch,
..
} = self;
let y_plane = row.y();
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
if let Some(buf) = luma.as_deref_mut() {
gray16_to_luma_row::<BE>(
y_plane,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
if let Some(buf) = luma_u16.as_deref_mut() {
gray16_to_luma_u16_row::<BE>(
y_plane,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
let want_rgb_u16 = rgb_u16.is_some();
let want_rgba_u16 = rgba_u16.is_some();
if want_rgba_u16 && !want_rgb_u16 {
let rgba_u16_buf = rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row =
rgba_u16_plane_row_slice(rgba_u16_buf, one_plane_start, one_plane_end, w, h)?;
gray16_to_rgba_u16_row::<BE>(y_plane, rgba_u16_row, w, use_simd, full_range);
} else if want_rgb_u16 {
let rgb_u16_buf = rgb_u16.as_deref_mut().unwrap();
let rgb_plane_start = one_plane_start * 3;
let rgb_plane_end =
one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
let rgb_u16_row = &mut rgb_u16_buf[rgb_plane_start..rgb_plane_end];
gray16_to_rgb_u16_row::<BE>(y_plane, rgb_u16_row, w, use_simd, full_range);
if want_rgba_u16 {
let rgba_u16_buf = rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row =
rgba_u16_plane_row_slice(rgba_u16_buf, one_plane_start, one_plane_end, w, h)?;
expand_rgb_u16_to_rgba_u16_row::<BITS>(rgb_u16_row, rgba_u16_row, w);
}
}
let want_rgb = rgb.is_some();
let want_rgba = rgba.is_some();
let want_hsv = hsv.is_some();
let need_rgb_kernel = want_rgb || (want_hsv && want_rgba);
if want_rgba && !need_rgb_kernel && !want_hsv {
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)?;
gray16_to_rgba_row::<BE>(y_plane, rgba_row, w, use_simd, full_range);
return Ok(());
}
if want_hsv && !want_rgb {
let hsv = hsv.as_mut().unwrap();
let (hp, sp, vp) = hsv.hsv();
gray16_to_hsv_row::<BE>(
y_plane,
&mut hp[one_plane_start..one_plane_end],
&mut sp[one_plane_start..one_plane_end],
&mut vp[one_plane_start..one_plane_end],
w,
use_simd,
full_range,
);
if let Some(buf) = rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
gray16_to_rgba_row::<BE>(y_plane, rgba_row, w, use_simd, full_range);
}
return Ok(());
}
if !need_rgb_kernel {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
gray16_to_rgb_row::<BE>(y_plane, rgb_row, w, use_simd, full_range);
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)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
}
Ok(())
}
}
impl<'a, const BE: bool> MixedSinker<'a, Grayf32<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_luma_f32(mut self, buf: &'a mut [f32]) -> Result<Self, MixedSinkerError> {
self.set_luma_f32(buf)?;
Ok(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_luma_f32(&mut self, buf: &'a mut [f32]) -> Result<&mut Self, MixedSinkerError> {
let expected = self.frame_elems(1)?;
if buf.len() < expected {
return Err(MixedSinkerError::InsufficientLumaF32Buffer(
InsufficientBuffer::new(expected, buf.len()),
));
}
self.luma_f32 = Some(buf);
Ok(self)
}
}
impl<const BE: bool> Grayf32Sink<BE> for MixedSinker<'_, Grayf32<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, Grayf32<BE>> {
type Input<'r> = Grayf32Row<'r>;
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: Grayf32Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.y().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Y,
idx,
w,
row.y().len(),
)));
}
if idx >= h {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, h),
));
}
let y_plane = row.y();
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
if let Some(buf) = self.luma_f32.as_deref_mut() {
grayf32_to_luma_f32_row::<BE>(
y_plane,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
if let Some(buf) = self.rgb_f32.as_deref_mut() {
let rgb_f32_start = one_plane_start * 3;
let rgb_f32_end = one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
grayf32_to_rgb_f32_row::<BE>(y_plane, &mut buf[rgb_f32_start..rgb_f32_end], w, use_simd);
}
if let Some(buf) = self.luma.as_deref_mut() {
grayf32_to_luma_row::<BE>(
y_plane,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
if let Some(buf) = self.luma_u16.as_deref_mut() {
grayf32_to_luma_u16_row::<BE>(
y_plane,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
let want_rgb_u16 = self.rgb_u16.is_some();
let want_rgba_u16 = self.rgba_u16.is_some();
if want_rgba_u16 && !want_rgb_u16 {
let rgba_u16_buf = self.rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row =
rgba_u16_plane_row_slice(rgba_u16_buf, one_plane_start, one_plane_end, w, h)?;
grayf32_to_rgba_u16_row::<BE>(y_plane, rgba_u16_row, w, use_simd);
} else if want_rgb_u16 {
let rgb_u16_buf = self.rgb_u16.as_deref_mut().unwrap();
let rgb_plane_start = one_plane_start * 3;
let rgb_plane_end =
one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
let rgb_u16_row = &mut rgb_u16_buf[rgb_plane_start..rgb_plane_end];
grayf32_to_rgb_u16_row::<BE>(y_plane, rgb_u16_row, w, use_simd);
if want_rgba_u16 {
let rgba_u16_buf = self.rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row =
rgba_u16_plane_row_slice(rgba_u16_buf, one_plane_start, one_plane_end, w, h)?;
expand_rgb_u16_to_rgba_u16_row::<16>(rgb_u16_row, rgba_u16_row, w);
}
}
let want_rgb = self.rgb.is_some();
let want_rgba = self.rgba.is_some();
let want_hsv = self.hsv.is_some();
if want_rgba && !want_rgb && !want_hsv {
let rgba_buf = self.rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?;
grayf32_to_rgba_row::<BE>(y_plane, rgba_row, w, use_simd);
return Ok(());
}
if want_hsv && !want_rgb {
let hsv = self.hsv.as_mut().unwrap();
let (hp, sp, vp) = hsv.hsv();
grayf32_to_hsv_row::<BE>(
y_plane,
&mut hp[one_plane_start..one_plane_end],
&mut sp[one_plane_start..one_plane_end],
&mut vp[one_plane_start..one_plane_end],
w,
use_simd,
);
if let Some(buf) = self.rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
grayf32_to_rgba_row::<BE>(y_plane, rgba_row, w, use_simd);
}
return Ok(());
}
if !want_rgb && !want_rgba && !want_hsv {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
self.rgb.as_deref_mut(),
&mut self.rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
grayf32_to_rgb_row::<BE>(y_plane, rgb_row, w, use_simd);
if let Some(hsv) = self.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) = self.rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Ya8> {
#[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)
}
}
impl Ya8Sink for MixedSinker<'_, Ya8> {}
impl PixelSink for MixedSinker<'_, Ya8> {
type Input<'r> = Ya8Row<'r>;
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: Ya8Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
let packed = row.packed();
if packed.len() != w * 2 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Y,
idx,
w * 2,
packed.len(),
)));
}
if idx >= h {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, h),
));
}
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
if let Some(buf) = self.luma.as_deref_mut() {
ya8_to_luma_row(
packed,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
if let Some(buf) = self.luma_u16.as_deref_mut() {
ya8_to_luma_u16_row(
packed,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
if let Some(buf) = self.rgb_u16.as_deref_mut() {
let rgb_plane_start = one_plane_start * 3;
let rgb_plane_end =
one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
ya8_to_rgb_u16_row(
packed,
&mut buf[rgb_plane_start..rgb_plane_end],
w,
use_simd,
);
}
if let Some(buf) = self.rgba_u16.as_deref_mut() {
let rgba_u16_row = rgba_u16_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
ya8_to_rgba_u16_row(packed, rgba_u16_row, w, use_simd);
}
let want_rgb = self.rgb.is_some();
let want_rgba = self.rgba.is_some();
let want_hsv = self.hsv.is_some();
if want_rgba && !want_rgb && !want_hsv {
let rgba_buf = self.rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?;
ya8_to_rgba_row(packed, rgba_row, w, use_simd);
return Ok(());
}
if want_hsv && !want_rgb && !want_rgba {
let hsv = self.hsv.as_mut().unwrap();
let (h, s, v) = hsv.hsv();
ya8_to_hsv_row(
packed,
&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,
);
return Ok(());
}
if !want_rgb && !want_rgba && !want_hsv {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
self.rgb.as_deref_mut(),
&mut self.rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
ya8_to_rgb_row(packed, rgb_row, w, use_simd);
if let Some(hsv) = self.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) = self.rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
copy_alpha_ya_u8(packed, rgba_row, w);
}
Ok(())
}
}
impl<'a, const BE: bool> MixedSinker<'a, Ya16<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)
}
}
impl<const BE: bool> Ya16Sink<BE> for MixedSinker<'_, Ya16<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, Ya16<BE>> {
type Input<'r> = Ya16Row<'r>;
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: Ya16Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
let packed = row.packed();
if packed.len() != w * 2 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Y,
idx,
w * 2,
packed.len(),
)));
}
if idx >= h {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, h),
));
}
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
if let Some(buf) = self.luma.as_deref_mut() {
ya16_to_luma_row::<BE>(
packed,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
if let Some(buf) = self.luma_u16.as_deref_mut() {
ya16_to_luma_u16_row::<BE>(
packed,
&mut buf[one_plane_start..one_plane_end],
w,
use_simd,
);
}
let want_rgb_u16 = self.rgb_u16.is_some();
let want_rgba_u16 = self.rgba_u16.is_some();
if want_rgba_u16 && !want_rgb_u16 {
let rgba_u16_buf = self.rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row =
rgba_u16_plane_row_slice(rgba_u16_buf, one_plane_start, one_plane_end, w, h)?;
ya16_to_rgba_u16_row::<BE>(packed, rgba_u16_row, w, use_simd);
} else if want_rgb_u16 {
let rgb_u16_buf = self.rgb_u16.as_deref_mut().unwrap();
let rgb_plane_start = one_plane_start * 3;
let rgb_plane_end =
one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
let rgb_u16_row = &mut rgb_u16_buf[rgb_plane_start..rgb_plane_end];
ya16_to_rgb_u16_row::<BE>(packed, rgb_u16_row, w, use_simd);
if want_rgba_u16 {
let rgba_u16_buf = self.rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row =
rgba_u16_plane_row_slice(rgba_u16_buf, one_plane_start, one_plane_end, w, h)?;
expand_rgb_u16_to_rgba_u16_row::<16>(rgb_u16_row, rgba_u16_row, w);
copy_alpha_ya_u16::<BE>(packed, rgba_u16_row, w);
}
}
let want_rgb = self.rgb.is_some();
let want_rgba = self.rgba.is_some();
let want_hsv = self.hsv.is_some();
if want_rgba && !want_rgb && !want_hsv {
let rgba_buf = self.rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?;
ya16_to_rgba_row::<BE>(packed, rgba_row, w, use_simd);
return Ok(());
}
if want_hsv && !want_rgb && !want_rgba {
let hsv = self.hsv.as_mut().unwrap();
let (h, s, v) = hsv.hsv();
ya16_to_hsv_row::<BE>(
packed,
&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,
);
return Ok(());
}
if !want_rgb && !want_rgba && !want_hsv {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
self.rgb.as_deref_mut(),
&mut self.rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
ya16_to_rgb_row::<BE>(packed, rgb_row, w, use_simd);
if let Some(hsv) = self.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) = self.rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
copy_alpha_ya_u16_to_u8::<BE>(packed, rgba_row, w);
}
Ok(())
}
}