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::{
alpha_extract, expand_rgb_to_rgba_row, expand_rgb_u16_to_rgba_u16_row,
gbr_to_luma_u16_high_bit_row, gbr_to_rgb_high_bit_row, gbr_to_rgb_u16_high_bit_row,
gbr_to_rgba_opaque_high_bit_row, gbr_to_rgba_opaque_u16_high_bit_row,
gbra_to_rgba_high_bit_row, gbra_to_rgba_u16_high_bit_row, rgb_to_hsv_row, rgb_to_luma_row,
},
};
macro_rules! impl_gbrp_high_bit {
($marker:ident, $sink:ident, $row:ident, $bits:literal) => {
impl<'a, const BE: bool> MixedSinker<'a, crate::source::$marker<BE>> {
#[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(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_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> crate::source::$sink<BE> for MixedSinker<'_, crate::source::$marker<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, crate::source::$marker<BE>> {
type Input<'r> = crate::source::$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: crate::source::$row<'_>) -> Result<(), Self::Error> {
const BITS: u32 = $bits;
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.g().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::GPlane,
idx,
w,
row.g().len(),
)));
}
if row.b().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::BPlane,
idx,
w,
row.b().len(),
)));
}
if row.r().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::RPlane,
idx,
w,
row.r().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 one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let g_in = row.g();
let b_in = row.b();
let r_in = row.r();
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)?;
gbr_to_rgba_opaque_u16_high_bit_row::<BITS, BE>(
g_in,
b_in,
r_in,
rgba_u16_row,
w,
use_simd,
);
} else if want_rgb_u16 {
let rgb_u16_buf = rgb_u16.as_deref_mut().unwrap();
let rgb_plane_end =
one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
let rgb_plane_start = one_plane_start * 3;
let rgb_u16_row = &mut rgb_u16_buf[rgb_plane_start..rgb_plane_end];
gbr_to_rgb_u16_high_bit_row::<BITS, BE>(g_in, b_in, r_in, rgb_u16_row, w, use_simd);
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);
}
}
if let Some(luma_u16_buf) = luma_u16.as_deref_mut() {
gbr_to_luma_u16_high_bit_row::<BITS, BE>(
g_in,
b_in,
r_in,
&mut luma_u16_buf[one_plane_start..one_plane_end],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
let want_rgb = rgb.is_some();
let want_rgba = rgba.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_staging = want_rgb || want_luma || want_hsv;
if want_rgba && !need_rgb_staging {
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)?;
gbr_to_rgba_opaque_high_bit_row::<BITS, BE>(g_in, b_in, r_in, rgba_row, w, use_simd);
return Ok(());
}
if !need_rgb_staging && !want_rgba {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
gbr_to_rgb_high_bit_row::<BITS, BE>(g_in, b_in, r_in, rgb_row, w, use_simd);
if let Some(luma) = luma.as_deref_mut() {
rgb_to_luma_row(
rgb_row,
&mut luma[one_plane_start..one_plane_end],
w,
row.matrix(),
row.full_range(),
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)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
}
Ok(())
}
}
};
}
macro_rules! impl_gbrap_high_bit {
($marker:ident, $sink:ident, $row:ident, $bits:literal) => {
impl<'a, const BE: bool> MixedSinker<'a, crate::source::$marker<BE>> {
#[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(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_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> crate::source::$sink<BE> for MixedSinker<'_, crate::source::$marker<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, crate::source::$marker<BE>> {
type Input<'r> = crate::source::$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: crate::source::$row<'_>) -> Result<(), Self::Error> {
const BITS: u32 = $bits;
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.g().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::GPlane,
idx,
w,
row.g().len(),
)));
}
if row.b().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::BPlane,
idx,
w,
row.b().len(),
)));
}
if row.r().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::RPlane,
idx,
w,
row.r().len(),
)));
}
if row.a().len() != w {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::AFull,
idx,
w,
row.a().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 one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let g_in = row.g();
let b_in = row.b();
let r_in = row.r();
let a_in = row.a();
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)?;
gbra_to_rgba_u16_high_bit_row::<BITS, BE>(
g_in,
b_in,
r_in,
a_in,
rgba_u16_row,
w,
use_simd,
);
} else if want_rgb_u16 {
let rgb_u16_buf = rgb_u16.as_deref_mut().unwrap();
let rgb_plane_end =
one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
let rgb_plane_start = one_plane_start * 3;
let rgb_u16_row = &mut rgb_u16_buf[rgb_plane_start..rgb_plane_end];
gbr_to_rgb_u16_high_bit_row::<BITS, BE>(g_in, b_in, r_in, rgb_u16_row, w, use_simd);
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);
alpha_extract::copy_alpha_plane_u16::<BITS, BE>(a_in, rgba_u16_row, w, use_simd);
}
}
if let Some(luma_u16_buf) = luma_u16.as_deref_mut() {
gbr_to_luma_u16_high_bit_row::<BITS, BE>(
g_in,
b_in,
r_in,
&mut luma_u16_buf[one_plane_start..one_plane_end],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
let want_rgb = rgb.is_some();
let want_rgba = rgba.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_staging = want_rgb || want_luma || want_hsv;
if want_rgba && !need_rgb_staging {
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)?;
gbra_to_rgba_high_bit_row::<BITS, BE>(g_in, b_in, r_in, a_in, rgba_row, w, use_simd);
return Ok(());
}
if !need_rgb_staging && !want_rgba {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
gbr_to_rgb_high_bit_row::<BITS, BE>(g_in, b_in, r_in, rgb_row, w, use_simd);
if let Some(luma) = luma.as_deref_mut() {
rgb_to_luma_row(
rgb_row,
&mut luma[one_plane_start..one_plane_end],
w,
row.matrix(),
row.full_range(),
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)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
alpha_extract::copy_alpha_plane_u16_to_u8::<BITS, BE>(a_in, rgba_row, w, use_simd);
}
Ok(())
}
}
};
}
impl_gbrp_high_bit!(Gbrp9, Gbrp9Sink, Gbrp9Row, 9);
impl_gbrp_high_bit!(Gbrp10, Gbrp10Sink, Gbrp10Row, 10);
impl_gbrp_high_bit!(Gbrp12, Gbrp12Sink, Gbrp12Row, 12);
impl_gbrp_high_bit!(Gbrp14, Gbrp14Sink, Gbrp14Row, 14);
impl_gbrp_high_bit!(Gbrp16, Gbrp16Sink, Gbrp16Row, 16);
impl_gbrap_high_bit!(Gbrap10, Gbrap10Sink, Gbrap10Row, 10);
impl_gbrap_high_bit!(Gbrap12, Gbrap12Sink, Gbrap12Row, 12);
impl_gbrap_high_bit!(Gbrap14, Gbrap14Sink, Gbrap14Row, 14);
impl_gbrap_high_bit!(Gbrap16, Gbrap16Sink, Gbrap16Row, 16);