use crate::factory::Rgb30;
use crate::image_store::CheckStoreDensity;
use crate::validation::{try_vec, validate_scratch, validate_sizes};
use crate::{BufferStore, ImageSize, ImageStore, ImageStoreMut, PicScaleError, ResamplingPlan};
use std::sync::Arc;
pub(crate) trait Ar30Destructuring {
fn decompose(&self, store: &ImageStore<'_, u8, 4>, into: &mut ImageStoreMut<u16, 3>);
fn compose(&self, store: &ImageStore<u16, 3>, into: &mut ImageStoreMut<'_, u8, 4>);
}
pub(crate) struct Ar30DestructuringImpl<const BYTES: usize> {
pub(crate) rgb30: Rgb30,
}
impl<const BYTES: usize> Ar30Destructuring for Ar30DestructuringImpl<BYTES> {
fn decompose(&self, store: &ImageStore<'_, u8, 4>, into: &mut ImageStoreMut<u16, 3>) {
match self.rgb30 {
Rgb30::Ar30 => {
for (dst, src) in into
.buffer
.borrow_mut()
.as_chunks_mut::<3>()
.0
.iter_mut()
.zip(store.buffer.as_chunks::<4>().0.iter())
{
let unpacked = Rgb30::Ar30
.unpack::<BYTES>(u32::from_ne_bytes([src[0], src[1], src[2], src[3]]));
dst[0] = unpacked.0 as u16;
dst[1] = unpacked.1 as u16;
dst[2] = unpacked.2 as u16;
}
}
Rgb30::Ra30 => {
for (dst, src) in into
.buffer
.borrow_mut()
.as_chunks_mut::<3>()
.0
.iter_mut()
.zip(store.buffer.as_chunks::<4>().0.iter())
{
let unpacked = Rgb30::Ra30
.unpack::<BYTES>(u32::from_ne_bytes([src[0], src[1], src[2], src[3]]));
dst[0] = unpacked.0 as u16;
dst[1] = unpacked.1 as u16;
dst[2] = unpacked.2 as u16;
}
}
}
}
fn compose(&self, store: &ImageStore<u16, 3>, into: &mut ImageStoreMut<'_, u8, 4>) {
match self.rgb30 {
Rgb30::Ar30 => {
for (dst, src) in into
.buffer
.borrow_mut()
.as_chunks_mut::<4>()
.0
.iter_mut()
.zip(store.buffer.as_chunks::<3>().0.iter())
{
let packed = Rgb30::Ar30.pack_w_a::<BYTES>(
src[0] as i32,
src[1] as i32,
src[2] as i32,
3,
);
let target_bytes = packed.to_ne_bytes();
dst[0] = target_bytes[0];
dst[1] = target_bytes[1];
dst[2] = target_bytes[2];
dst[3] = target_bytes[3];
}
}
Rgb30::Ra30 => {
for (dst, src) in into
.buffer
.borrow_mut()
.as_chunks_mut::<4>()
.0
.iter_mut()
.zip(store.buffer.as_chunks::<3>().0.iter())
{
let packed = Rgb30::Ra30.pack_w_a::<BYTES>(
src[0] as i32,
src[1] as i32,
src[2] as i32,
3,
);
let target_bytes = packed.to_ne_bytes();
dst[0] = target_bytes[0];
dst[1] = target_bytes[1];
dst[2] = target_bytes[2];
dst[3] = target_bytes[3];
}
}
}
}
}
struct ScratchLayout {
inner_filter_size: usize,
src_rgb16_size: usize,
tgt_rgb16_size: usize,
}
impl ScratchLayout {
fn new(plan: &Ar30Plan) -> Self {
Self {
inner_filter_size: plan.inner_filter.scratch_size() * size_of::<u16>() + 2,
src_rgb16_size: plan.source_size.height * plan.source_size.width * 3 * size_of::<u16>()
+ 2,
tgt_rgb16_size: plan.target_size.height * plan.target_size.width * 3 * size_of::<u16>()
+ 2,
}
}
fn total(&self) -> usize {
self.inner_filter_size + self.src_rgb16_size + self.tgt_rgb16_size
}
}
pub(crate) struct Ar30Plan {
pub(crate) source_size: ImageSize,
pub(crate) target_size: ImageSize,
pub(crate) inner_filter: Arc<dyn ResamplingPlan<u16, 3> + Send + Sync>,
pub(crate) decomposer: Arc<dyn Ar30Destructuring + Send + Sync>,
}
impl ResamplingPlan<u8, 4> for Ar30Plan {
fn resample(
&self,
store: &ImageStore<'_, u8, 4>,
into: &mut ImageStoreMut<'_, u8, 4>,
) -> Result<(), PicScaleError> {
let mut scratch = try_vec![u8::default(); self.scratch_size()];
self.resample_with_scratch(store, into, &mut scratch)
}
fn resample_with_scratch(
&self,
store: &ImageStore<'_, u8, 4>,
into: &mut ImageStoreMut<'_, u8, 4>,
scratch: &mut [u8],
) -> Result<(), PicScaleError> {
validate_sizes!(store, into, self.source_size, self.target_size);
let scratch = validate_scratch!(scratch, self.scratch_size());
if into.should_have_bit_depth() && !(1..=16).contains(&into.bit_depth) {
return Err(PicScaleError::UnsupportedBitDepth(into.bit_depth));
}
let scratch_rgb16_image_size = self.source_size.height * self.source_size.width * 3;
let scratch_target_rgb16_image_size = self.target_size.height * self.target_size.width * 3;
let scratch_layout = ScratchLayout::new(self);
let (inner_filter_scratch, tail0) = scratch.split_at_mut(scratch_layout.inner_filter_size);
let (ar30_image_scratch_u8, tail1) = tail0.split_at_mut(scratch_layout.src_rgb16_size);
let (ar30_target_scratch_u8, _) = tail1.split_at_mut(scratch_layout.tgt_rgb16_size);
let (ar30_image_scratch, _) =
mangle_slice_u8_as_u16(ar30_image_scratch_u8).split_at_mut(scratch_rgb16_image_size);
let (inner_filter_scratch, _) = mangle_slice_u8_as_u16(inner_filter_scratch)
.split_at_mut(self.inner_filter.scratch_size());
let (ar30_target_scratch, _) = mangle_slice_u8_as_u16(ar30_target_scratch_u8)
.split_at_mut(scratch_target_rgb16_image_size);
let mut ar30_image = ImageStoreMut::<u16, 3> {
buffer: BufferStore::Borrowed(ar30_image_scratch),
channels: 3,
width: store.width,
height: store.height,
stride: store.width * 3,
bit_depth: 10,
};
self.decomposer.decompose(store, &mut ar30_image);
let fixed_ar30 = ar30_image.to_immutable();
let mut ar30_image_target = ImageStoreMut::<u16, 3> {
buffer: BufferStore::Borrowed(ar30_target_scratch),
channels: 3,
width: into.width,
height: into.height,
stride: into.width * 3,
bit_depth: 10,
};
self.inner_filter.resample_with_scratch(
&fixed_ar30,
&mut ar30_image_target,
inner_filter_scratch,
)?;
let fixed_target = ar30_image_target.to_immutable();
self.decomposer.compose(&fixed_target, into);
Ok(())
}
fn alloc_scratch(&self) -> Vec<u8> {
vec![u8::default(); self.scratch_size()]
}
fn scratch_size(&self) -> usize {
let layout = ScratchLayout::new(self);
layout.total()
}
fn target_size(&self) -> ImageSize {
self.target_size
}
fn source_size(&self) -> ImageSize {
self.source_size
}
}
fn mangle_slice_u8_as_u16(slice: &mut [u8]) -> &mut [u16] {
let (_, middle, _) = unsafe { slice.align_to_mut::<u16>() };
middle
}