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::{
bgr444_to_rgb_row, bgr444_to_rgb_u16_row, bgr444_to_rgba_row, bgr444_to_rgba_u16_row,
bgr555_to_rgb_row, bgr555_to_rgb_u16_row, bgr555_to_rgba_row, bgr555_to_rgba_u16_row,
bgr565_to_rgb_row, bgr565_to_rgb_u16_row, bgr565_to_rgba_row, bgr565_to_rgba_u16_row,
rgb_to_hsv_row, rgb_to_luma_row, rgb_to_luma_u16_row, rgb444_to_rgb_row, rgb444_to_rgb_u16_row,
rgb444_to_rgba_row, rgb444_to_rgba_u16_row, rgb555_to_rgb_row, rgb555_to_rgb_u16_row,
rgb555_to_rgba_row, rgb555_to_rgba_u16_row, rgb565_to_rgb_row, rgb565_to_rgb_u16_row,
rgb565_to_rgba_row, rgb565_to_rgba_u16_row,
},
source::{
Bgr444, Bgr444Row, Bgr444Sink, Bgr555, Bgr555Row, Bgr555Sink, Bgr565, Bgr565Row, Bgr565Sink,
Rgb444, Rgb444Row, Rgb444Sink, Rgb555, Rgb555Row, Rgb555Sink, Rgb565, Rgb565Row, Rgb565Sink,
},
};
#[inline(always)]
fn rgb_u16_plane_row_slice(
buf: &mut [u16],
one_plane_start: usize,
one_plane_end: usize,
width: usize,
height: usize,
) -> Result<&mut [u16], MixedSinkerError> {
let end = one_plane_end
.checked_mul(3)
.ok_or(MixedSinkerError::GeometryOverflow(GeometryOverflow::new(
width, height, 3,
)))?;
let start = one_plane_start * 3;
Ok(&mut buf[start..end])
}
macro_rules! impl_legacy_rgb_sinker {
(
marker: $marker:ident,
sink_trait: $sink_trait:ident,
row_ty: $row_ty:ident,
buf_field: $buf_field:ident,
row_slice: $row_slice:expr,
to_rgb: $to_rgb:ident,
to_rgba: $to_rgba:ident,
to_rgb_u16: $to_rgb_u16:ident,
to_rgba_u16: $to_rgba_u16:ident,
) => {
impl<'a> MixedSinker<'a, $marker> {
#[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 $sink_trait for MixedSinker<'_, $marker> {}
impl PixelSink for MixedSinker<'_, $marker> {
type Input<'r> = $row_ty<'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_ty<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.$buf_field().len() != w * 2 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
$row_slice,
idx,
w * 2,
row.$buf_field().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 one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let src = row.$buf_field();
if let Some(buf) = rgb_u16.as_deref_mut() {
let rgb_u16_row = rgb_u16_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
$to_rgb_u16(src, rgb_u16_row, w, use_simd);
}
if let Some(buf) = rgba_u16.as_deref_mut() {
let rgba_u16_row = rgba_u16_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
$to_rgba_u16(src, rgba_u16_row, w, use_simd);
}
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 {
if let Some(buf) = rgba.as_deref_mut() {
let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?;
$to_rgba(src, rgba_row, w, use_simd);
}
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
$to_rgb(src, rgb_row, w, use_simd);
if let Some(luma_buf) = luma.as_deref_mut() {
rgb_to_luma_row(
rgb_row,
&mut luma_buf[one_plane_start..one_plane_end],
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[one_plane_start..one_plane_end],
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[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)?;
$to_rgba(src, rgba_row, w, use_simd);
}
Ok(())
}
}
};
}
impl_legacy_rgb_sinker! {
marker: Rgb565,
sink_trait: Rgb565Sink,
row_ty: Rgb565Row,
buf_field: rgb565,
row_slice: RowSlice::Rgb565Packed,
to_rgb: rgb565_to_rgb_row,
to_rgba: rgb565_to_rgba_row,
to_rgb_u16: rgb565_to_rgb_u16_row,
to_rgba_u16: rgb565_to_rgba_u16_row,
}
impl_legacy_rgb_sinker! {
marker: Bgr565,
sink_trait: Bgr565Sink,
row_ty: Bgr565Row,
buf_field: bgr565,
row_slice: RowSlice::Bgr565Packed,
to_rgb: bgr565_to_rgb_row,
to_rgba: bgr565_to_rgba_row,
to_rgb_u16: bgr565_to_rgb_u16_row,
to_rgba_u16: bgr565_to_rgba_u16_row,
}
impl_legacy_rgb_sinker! {
marker: Rgb555,
sink_trait: Rgb555Sink,
row_ty: Rgb555Row,
buf_field: rgb555,
row_slice: RowSlice::Rgb555Packed,
to_rgb: rgb555_to_rgb_row,
to_rgba: rgb555_to_rgba_row,
to_rgb_u16: rgb555_to_rgb_u16_row,
to_rgba_u16: rgb555_to_rgba_u16_row,
}
impl_legacy_rgb_sinker! {
marker: Bgr555,
sink_trait: Bgr555Sink,
row_ty: Bgr555Row,
buf_field: bgr555,
row_slice: RowSlice::Bgr555Packed,
to_rgb: bgr555_to_rgb_row,
to_rgba: bgr555_to_rgba_row,
to_rgb_u16: bgr555_to_rgb_u16_row,
to_rgba_u16: bgr555_to_rgba_u16_row,
}
impl_legacy_rgb_sinker! {
marker: Rgb444,
sink_trait: Rgb444Sink,
row_ty: Rgb444Row,
buf_field: rgb444,
row_slice: RowSlice::Rgb444Packed,
to_rgb: rgb444_to_rgb_row,
to_rgba: rgb444_to_rgba_row,
to_rgb_u16: rgb444_to_rgb_u16_row,
to_rgba_u16: rgb444_to_rgba_u16_row,
}
impl_legacy_rgb_sinker! {
marker: Bgr444,
sink_trait: Bgr444Sink,
row_ty: Bgr444Row,
buf_field: bgr444,
row_slice: RowSlice::Bgr444Packed,
to_rgb: bgr444_to_rgb_row,
to_rgba: bgr444_to_rgba_row,
to_rgb_u16: bgr444_to_rgb_u16_row,
to_rgba_u16: bgr444_to_rgba_u16_row,
}