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::{
bgr48_to_rgb_row_endian, bgr48_to_rgb_u16_row_endian, bgr48_to_rgba_row_endian,
bgr48_to_rgba_u16_row_endian, bgra64_to_rgb_row_endian, bgra64_to_rgb_u16_row_endian,
bgra64_to_rgba_row_endian, bgra64_to_rgba_u16_row_endian, expand_rgb_to_rgba_row,
expand_rgb_u16_to_rgba_u16_row, rgb_to_hsv_row, rgb_to_luma_row, rgb_to_luma_u16_row,
rgb48_to_rgb_row_endian, rgb48_to_rgb_u16_row_endian, rgb48_to_rgba_row_endian,
rgb48_to_rgba_u16_row_endian, rgba64_to_rgb_row_endian, rgba64_to_rgb_u16_row_endian,
rgba64_to_rgba_row_endian, rgba64_to_rgba_u16_row_endian,
},
source::{
Bgr48, Bgr48Row, Bgr48Sink, Bgra64, Bgra64Row, Bgra64Sink, Rgb48, Rgb48Row, Rgb48Sink, Rgba64,
Rgba64Row, Rgba64Sink,
},
};
impl<'a, const BE: bool> MixedSinker<'a, Rgb48<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> Rgb48Sink<BE> for MixedSinker<'_, Rgb48<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, Rgb48<BE>> {
type Input<'r> = Rgb48Row<'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: Rgb48Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
let packed_expected =
w.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
if row.rgb48().len() != packed_expected {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Rgb48Packed,
idx,
packed_expected,
row.rgb48().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgb_u16,
rgba,
rgba_u16,
luma,
luma_u16,
hsv,
rgb_scratch,
..
} = self;
let ps = idx * w;
let pe = ps + w;
let in48 = row.rgb48();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_luma_u16 = luma_u16.is_some();
let want_hsv = hsv.is_some();
let need_u8_rgb = want_rgb || want_luma || want_luma_u16 || want_hsv;
if need_u8_rgb {
let rgb_row = rgb_row_buf_or_scratch(rgb.as_deref_mut(), rgb_scratch, ps, pe, w, h)?;
rgb48_to_rgb_row_endian::<BE>(in48, rgb_row, w, use_simd);
if let Some(luma_buf) = luma.as_deref_mut() {
rgb_to_luma_row(
rgb_row,
&mut luma_buf[ps..pe],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
if let Some(luma_u16_buf) = luma_u16.as_deref_mut() {
rgb_to_luma_u16_row(
rgb_row,
&mut luma_u16_buf[ps..pe],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
if let Some(hsv_bufs) = hsv.as_mut() {
let (h, s, v) = hsv_bufs.hsv();
rgb_to_hsv_row(
rgb_row,
&mut h[ps..pe],
&mut s[ps..pe],
&mut v[ps..pe],
w,
use_simd,
);
}
}
if let Some(buf) = rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, ps, pe, w, h)?;
rgb48_to_rgba_row_endian::<BE>(in48, rgba_row, w, use_simd);
}
if let Some(buf) = rgb_u16.as_deref_mut() {
let end =
pe.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
rgb48_to_rgb_u16_row_endian::<BE>(in48, &mut buf[ps * 3..end], w, use_simd);
}
if let Some(buf) = rgba_u16.as_deref_mut() {
let rgba_u16_row = rgba_u16_plane_row_slice(buf, ps, pe, w, h)?;
rgb48_to_rgba_u16_row_endian::<BE>(in48, rgba_u16_row, w, use_simd);
}
Ok(())
}
}
impl<'a, const BE: bool> MixedSinker<'a, Bgr48<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> Bgr48Sink<BE> for MixedSinker<'_, Bgr48<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, Bgr48<BE>> {
type Input<'r> = Bgr48Row<'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: Bgr48Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
let packed_expected =
w.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
if row.bgr48().len() != packed_expected {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Bgr48Packed,
idx,
packed_expected,
row.bgr48().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgb_u16,
rgba,
rgba_u16,
luma,
luma_u16,
hsv,
rgb_scratch,
..
} = self;
let ps = idx * w;
let pe = ps + w;
let in48 = row.bgr48();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_luma_u16 = luma_u16.is_some();
let want_hsv = hsv.is_some();
let need_u8_rgb = want_rgb || want_luma || want_luma_u16 || want_hsv;
if need_u8_rgb {
let rgb_row = rgb_row_buf_or_scratch(rgb.as_deref_mut(), rgb_scratch, ps, pe, w, h)?;
bgr48_to_rgb_row_endian::<BE>(in48, rgb_row, w, use_simd);
if let Some(luma_buf) = luma.as_deref_mut() {
rgb_to_luma_row(
rgb_row,
&mut luma_buf[ps..pe],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
if let Some(luma_u16_buf) = luma_u16.as_deref_mut() {
rgb_to_luma_u16_row(
rgb_row,
&mut luma_u16_buf[ps..pe],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
if let Some(hsv_bufs) = hsv.as_mut() {
let (h, s, v) = hsv_bufs.hsv();
rgb_to_hsv_row(
rgb_row,
&mut h[ps..pe],
&mut s[ps..pe],
&mut v[ps..pe],
w,
use_simd,
);
}
}
if let Some(buf) = rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, ps, pe, w, h)?;
bgr48_to_rgba_row_endian::<BE>(in48, rgba_row, w, use_simd);
}
if let Some(buf) = rgb_u16.as_deref_mut() {
let end =
pe.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
bgr48_to_rgb_u16_row_endian::<BE>(in48, &mut buf[ps * 3..end], w, use_simd);
}
if let Some(buf) = rgba_u16.as_deref_mut() {
let rgba_u16_row = rgba_u16_plane_row_slice(buf, ps, pe, w, h)?;
bgr48_to_rgba_u16_row_endian::<BE>(in48, rgba_u16_row, w, use_simd);
}
Ok(())
}
}
impl<'a, const BE: bool> MixedSinker<'a, Rgba64<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> Rgba64Sink<BE> for MixedSinker<'_, Rgba64<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, Rgba64<BE>> {
type Input<'r> = Rgba64Row<'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: Rgba64Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
let packed_expected =
w.checked_mul(4)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 4,
)))?;
if row.rgba64().len() != packed_expected {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Rgba64Packed,
idx,
packed_expected,
row.rgba64().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgb_u16,
rgba,
rgba_u16,
luma,
luma_u16,
hsv,
rgb_scratch,
..
} = self;
let ps = idx * w;
let pe = ps + w;
let in64 = row.rgba64();
let want_rgb = rgb.is_some();
let want_rgba = rgba.is_some();
let want_luma = luma.is_some();
let want_luma_u16 = luma_u16.is_some();
let want_hsv = hsv.is_some();
let want_rgb_u16 = rgb_u16.is_some();
let want_rgba_u16 = rgba_u16.is_some();
let need_u8_rgb = want_rgb || want_luma || want_luma_u16 || want_hsv;
if want_rgba && !need_u8_rgb && !want_rgb_u16 && !want_rgba_u16 {
let rgba_buf = rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, ps, pe, w, h)?;
rgba64_to_rgba_row_endian::<BE>(in64, rgba_row, w, use_simd);
return Ok(());
}
if want_rgba_u16 && !want_rgb_u16 && !need_u8_rgb && !want_rgba {
let rgba_u16_buf = rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row = rgba_u16_plane_row_slice(rgba_u16_buf, ps, pe, w, h)?;
rgba64_to_rgba_u16_row_endian::<BE>(in64, rgba_u16_row, w, use_simd);
return Ok(());
}
if need_u8_rgb {
let rgb_row = rgb_row_buf_or_scratch(rgb.as_deref_mut(), rgb_scratch, ps, pe, w, h)?;
rgba64_to_rgb_row_endian::<BE>(in64, rgb_row, w, use_simd);
if let Some(luma_buf) = luma.as_deref_mut() {
rgb_to_luma_row(
rgb_row,
&mut luma_buf[ps..pe],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
if let Some(luma_u16_buf) = luma_u16.as_deref_mut() {
rgb_to_luma_u16_row(
rgb_row,
&mut luma_u16_buf[ps..pe],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
if let Some(hsv_bufs) = hsv.as_mut() {
let (h, s, v) = hsv_bufs.hsv();
rgb_to_hsv_row(
rgb_row,
&mut h[ps..pe],
&mut s[ps..pe],
&mut v[ps..pe],
w,
use_simd,
);
}
if want_rgba {
let rgba_buf = rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, ps, pe, w, h)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
crate::row::scalar::alpha_extract::copy_alpha_packed_u16x4_to_u8_at_3::<BE>(
in64, rgba_row, w,
);
}
}
if want_rgba && !need_u8_rgb {
let rgba_buf = rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, ps, pe, w, h)?;
rgba64_to_rgba_row_endian::<BE>(in64, rgba_row, w, use_simd);
}
if want_rgb_u16 {
let rgb_u16_buf = rgb_u16.as_deref_mut().unwrap();
let end =
pe.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
let rgb_u16_row = &mut rgb_u16_buf[ps * 3..end];
rgba64_to_rgb_u16_row_endian::<BE>(in64, 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, ps, pe, w, h)?;
expand_rgb_u16_to_rgba_u16_row::<16>(rgb_u16_row, rgba_u16_row, w);
crate::row::scalar::alpha_extract::copy_alpha_packed_u16x4_at_3::<BE>(
in64,
rgba_u16_row,
w,
);
}
}
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, ps, pe, w, h)?;
rgba64_to_rgba_u16_row_endian::<BE>(in64, rgba_u16_row, w, use_simd);
}
Ok(())
}
}
impl<'a, const BE: bool> MixedSinker<'a, Bgra64<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> Bgra64Sink<BE> for MixedSinker<'_, Bgra64<BE>> {}
impl<const BE: bool> PixelSink for MixedSinker<'_, Bgra64<BE>> {
type Input<'r> = Bgra64Row<'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: Bgra64Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
let packed_expected =
w.checked_mul(4)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 4,
)))?;
if row.bgra64().len() != packed_expected {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::Bgra64Packed,
idx,
packed_expected,
row.bgra64().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgb_u16,
rgba,
rgba_u16,
luma,
luma_u16,
hsv,
rgb_scratch,
..
} = self;
let ps = idx * w;
let pe = ps + w;
let in64 = row.bgra64();
let want_rgb = rgb.is_some();
let want_rgba = rgba.is_some();
let want_luma = luma.is_some();
let want_luma_u16 = luma_u16.is_some();
let want_hsv = hsv.is_some();
let want_rgb_u16 = rgb_u16.is_some();
let want_rgba_u16 = rgba_u16.is_some();
let need_u8_rgb = want_rgb || want_luma || want_luma_u16 || want_hsv;
if want_rgba && !need_u8_rgb && !want_rgb_u16 && !want_rgba_u16 {
let rgba_buf = rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, ps, pe, w, h)?;
bgra64_to_rgba_row_endian::<BE>(in64, rgba_row, w, use_simd);
return Ok(());
}
if want_rgba_u16 && !want_rgb_u16 && !need_u8_rgb && !want_rgba {
let rgba_u16_buf = rgba_u16.as_deref_mut().unwrap();
let rgba_u16_row = rgba_u16_plane_row_slice(rgba_u16_buf, ps, pe, w, h)?;
bgra64_to_rgba_u16_row_endian::<BE>(in64, rgba_u16_row, w, use_simd);
return Ok(());
}
if need_u8_rgb {
let rgb_row = rgb_row_buf_or_scratch(rgb.as_deref_mut(), rgb_scratch, ps, pe, w, h)?;
bgra64_to_rgb_row_endian::<BE>(in64, rgb_row, w, use_simd);
if let Some(luma_buf) = luma.as_deref_mut() {
rgb_to_luma_row(
rgb_row,
&mut luma_buf[ps..pe],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
if let Some(luma_u16_buf) = luma_u16.as_deref_mut() {
rgb_to_luma_u16_row(
rgb_row,
&mut luma_u16_buf[ps..pe],
w,
row.matrix(),
row.full_range(),
use_simd,
);
}
if let Some(hsv_bufs) = hsv.as_mut() {
let (h, s, v) = hsv_bufs.hsv();
rgb_to_hsv_row(
rgb_row,
&mut h[ps..pe],
&mut s[ps..pe],
&mut v[ps..pe],
w,
use_simd,
);
}
if want_rgba {
let rgba_buf = rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, ps, pe, w, h)?;
expand_rgb_to_rgba_row(rgb_row, rgba_row, w);
crate::row::scalar::alpha_extract::copy_alpha_packed_u16x4_to_u8_at_3::<BE>(
in64, rgba_row, w,
);
}
}
if want_rgba && !need_u8_rgb {
let rgba_buf = rgba.as_deref_mut().unwrap();
let rgba_row = rgba_plane_row_slice(rgba_buf, ps, pe, w, h)?;
bgra64_to_rgba_row_endian::<BE>(in64, rgba_row, w, use_simd);
}
if want_rgb_u16 {
let rgb_u16_buf = rgb_u16.as_deref_mut().unwrap();
let end =
pe.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
w, h, 3,
)))?;
let rgb_u16_row = &mut rgb_u16_buf[ps * 3..end];
bgra64_to_rgb_u16_row_endian::<BE>(in64, 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, ps, pe, w, h)?;
expand_rgb_u16_to_rgba_u16_row::<16>(rgb_u16_row, rgba_u16_row, w);
crate::row::scalar::alpha_extract::copy_alpha_packed_u16x4_at_3::<BE>(
in64,
rgba_u16_row,
w,
);
}
}
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, ps, pe, w, h)?;
bgra64_to_rgba_u16_row_endian::<BE>(in64, rgba_u16_row, w, use_simd);
}
Ok(())
}
}