use super::{
InsufficientBuffer, MixedSinker, MixedSinkerError, RowIndexOutOfRange, RowShapeMismatch,
RowSlice, check_dimensions_match, rgb_row_buf_or_scratch, rgba_plane_row_slice,
};
use crate::{
PixelSink,
row::{
abgr_to_rgb_row, abgr_to_rgba_row, argb_to_rgb_row, argb_to_rgba_row, bgr_to_rgb_row,
bgra_to_rgb_row, bgra_to_rgba_row, bgrx_to_rgba_row, expand_rgb_to_rgba_row, rgb_to_hsv_row,
rgb_to_luma_row, rgba_to_rgb_row, rgbx_to_rgba_row, xbgr_to_rgba_row, xrgb_to_rgba_row,
},
source::{
Abgr, AbgrRow, AbgrSink, Argb, ArgbRow, ArgbSink, Bgr24, Bgr24Row, Bgr24Sink, Bgra, BgraRow,
BgraSink, Bgrx, BgrxRow, BgrxSink, Rgb24, Rgb24Row, Rgb24Sink, Rgba, RgbaRow, RgbaSink, Rgbx,
RgbxRow, RgbxSink, Xbgr, XbgrRow, XbgrSink, Xrgb, XrgbRow, XrgbSink,
},
};
impl<'a> MixedSinker<'a, Rgb24> {
#[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)
}
}
impl Rgb24Sink for MixedSinker<'_, Rgb24> {}
impl PixelSink for MixedSinker<'_, Rgb24> {
type Input<'r> = Rgb24Row<'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: Rgb24Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.rgb().len() != w * 3 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::RgbPacked,
idx,
w * 3,
row.rgb().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch: _,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let rgb_in = row.rgb();
if let Some(luma) = luma.as_deref_mut() {
rgb_to_luma_row(
rgb_in,
&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_in,
&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(rgb_buf) = rgb.as_deref_mut() {
let rgb_start = one_plane_start * 3;
let rgb_end = one_plane_end * 3;
rgb_buf[rgb_start..rgb_end].copy_from_slice(rgb_in);
}
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_in, rgba_row, w);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Bgr24> {
#[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)
}
}
impl Bgr24Sink for MixedSinker<'_, Bgr24> {}
impl PixelSink for MixedSinker<'_, Bgr24> {
type Input<'r> = Bgr24Row<'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: Bgr24Row<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.bgr().len() != w * 3 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::BgrPacked,
idx,
w * 3,
row.bgr().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
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_buffer = want_rgb || want_rgba || want_luma || want_hsv;
if !need_rgb_buffer {
return Ok(());
}
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
bgr_to_rgb_row(row.bgr(), 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(())
}
}
impl<'a> MixedSinker<'a, Rgba> {
#[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)
}
}
impl RgbaSink for MixedSinker<'_, Rgba> {}
impl PixelSink for MixedSinker<'_, Rgba> {
type Input<'r> = RgbaRow<'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: RgbaRow<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.rgba().len() != w * 4 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::RgbaPacked,
idx,
w * 4,
row.rgba().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let rgba_in = row.rgba();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_buffer = want_rgb || want_luma || want_hsv;
if need_rgb_buffer {
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
rgba_to_rgb_row(rgba_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)?;
rgba_row.copy_from_slice(rgba_in);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Bgra> {
#[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)
}
}
impl BgraSink for MixedSinker<'_, Bgra> {}
impl PixelSink for MixedSinker<'_, Bgra> {
type Input<'r> = BgraRow<'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: BgraRow<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.bgra().len() != w * 4 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::BgraPacked,
idx,
w * 4,
row.bgra().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let bgra_in = row.bgra();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_buffer = want_rgb || want_luma || want_hsv;
if need_rgb_buffer {
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
bgra_to_rgb_row(bgra_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)?;
bgra_to_rgba_row(bgra_in, rgba_row, w, use_simd);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Argb> {
#[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)
}
}
impl ArgbSink for MixedSinker<'_, Argb> {}
impl PixelSink for MixedSinker<'_, Argb> {
type Input<'r> = ArgbRow<'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: ArgbRow<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.argb().len() != w * 4 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::ArgbPacked,
idx,
w * 4,
row.argb().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let argb_in = row.argb();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_buffer = want_rgb || want_luma || want_hsv;
if need_rgb_buffer {
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
argb_to_rgb_row(argb_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)?;
argb_to_rgba_row(argb_in, rgba_row, w, use_simd);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Abgr> {
#[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)
}
}
impl AbgrSink for MixedSinker<'_, Abgr> {}
impl PixelSink for MixedSinker<'_, Abgr> {
type Input<'r> = AbgrRow<'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: AbgrRow<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.abgr().len() != w * 4 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::AbgrPacked,
idx,
w * 4,
row.abgr().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let abgr_in = row.abgr();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_buffer = want_rgb || want_luma || want_hsv;
if need_rgb_buffer {
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
abgr_to_rgb_row(abgr_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)?;
abgr_to_rgba_row(abgr_in, rgba_row, w, use_simd);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Xrgb> {
#[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)
}
}
impl XrgbSink for MixedSinker<'_, Xrgb> {}
impl PixelSink for MixedSinker<'_, Xrgb> {
type Input<'r> = XrgbRow<'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: XrgbRow<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.xrgb().len() != w * 4 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::XrgbPacked,
idx,
w * 4,
row.xrgb().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let xrgb_in = row.xrgb();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_buffer = want_rgb || want_luma || want_hsv;
if need_rgb_buffer {
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
argb_to_rgb_row(xrgb_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)?;
xrgb_to_rgba_row(xrgb_in, rgba_row, w, use_simd);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Rgbx> {
#[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)
}
}
impl RgbxSink for MixedSinker<'_, Rgbx> {}
impl PixelSink for MixedSinker<'_, Rgbx> {
type Input<'r> = RgbxRow<'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: RgbxRow<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.rgbx().len() != w * 4 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::RgbxPacked,
idx,
w * 4,
row.rgbx().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let rgbx_in = row.rgbx();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_buffer = want_rgb || want_luma || want_hsv;
if need_rgb_buffer {
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
rgba_to_rgb_row(rgbx_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)?;
rgbx_to_rgba_row(rgbx_in, rgba_row, w, use_simd);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Xbgr> {
#[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)
}
}
impl XbgrSink for MixedSinker<'_, Xbgr> {}
impl PixelSink for MixedSinker<'_, Xbgr> {
type Input<'r> = XbgrRow<'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: XbgrRow<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.xbgr().len() != w * 4 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::XbgrPacked,
idx,
w * 4,
row.xbgr().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let xbgr_in = row.xbgr();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_buffer = want_rgb || want_luma || want_hsv;
if need_rgb_buffer {
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
abgr_to_rgb_row(xbgr_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)?;
xbgr_to_rgba_row(xbgr_in, rgba_row, w, use_simd);
}
Ok(())
}
}
impl<'a> MixedSinker<'a, Bgrx> {
#[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)
}
}
impl BgrxSink for MixedSinker<'_, Bgrx> {}
impl PixelSink for MixedSinker<'_, Bgrx> {
type Input<'r> = BgrxRow<'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: BgrxRow<'_>) -> Result<(), Self::Error> {
let w = self.width;
let h = self.height;
let idx = row.row();
let use_simd = self.simd;
if row.bgrx().len() != w * 4 {
return Err(MixedSinkerError::RowShapeMismatch(RowShapeMismatch::new(
RowSlice::BgrxPacked,
idx,
w * 4,
row.bgrx().len(),
)));
}
if idx >= self.height {
return Err(MixedSinkerError::RowIndexOutOfRange(
RowIndexOutOfRange::new(idx, self.height),
));
}
let Self {
rgb,
rgba,
luma,
hsv,
rgb_scratch,
..
} = self;
let one_plane_start = idx * w;
let one_plane_end = one_plane_start + w;
let bgrx_in = row.bgrx();
let want_rgb = rgb.is_some();
let want_luma = luma.is_some();
let want_hsv = hsv.is_some();
let need_rgb_buffer = want_rgb || want_luma || want_hsv;
if need_rgb_buffer {
let rgb_row = rgb_row_buf_or_scratch(
rgb.as_deref_mut(),
rgb_scratch,
one_plane_start,
one_plane_end,
w,
h,
)?;
bgra_to_rgb_row(bgrx_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)?;
bgrx_to_rgba_row(bgrx_in, rgba_row, w, use_simd);
}
Ok(())
}
}