use std::{
cmp::{max, min},
num::{NonZeroU8, NonZeroUsize},
};
use crate::util::Pixel;
use semisafe::slice::get as semisafe_get;
use semisafe::slice::get_mut as semisafe_get_mut;
pub(super) fn refine_horizontal_bicubic<T: Pixel>(
dest: &mut [T],
src: &[T],
pitch: NonZeroUsize,
width: NonZeroUsize,
height: NonZeroUsize,
bits_per_sample: NonZeroU8,
) {
let pixel_max = (1u32 << bits_per_sample.get()) - 1;
let mut offset = 0;
for _j in 0..height.get() {
let src_row = semisafe_get(semisafe_get(src, offset..), ..width.get());
let dest_row = semisafe_get_mut(semisafe_get_mut(dest, offset..), ..width.get());
let a: u32 = semisafe_get(src_row, 0).as_();
let b: u32 = semisafe_get(src_row, 1).as_();
*semisafe_get_mut(dest_row, 0) = T::from_u32_or_max_value((a + b + 1) / 2);
for i in 1..(width.get() - 3) {
let a: i32 = semisafe_get(src_row, i - 1).as_();
let b: i32 = semisafe_get(src_row, i).as_();
let c: i32 = semisafe_get(src_row, i + 1).as_();
let d: i32 = semisafe_get(src_row, i + 2).as_();
*semisafe_get_mut(dest_row, i) = T::from_u32_or_max_value(min(
pixel_max,
max(0, (-(a + d) + (b + c) * 9 + 8) >> 4) as u32,
));
}
for i in (width.get() - 3)..(width.get() - 1) {
let a: u32 = semisafe_get(src_row, i).as_();
let b: u32 = semisafe_get(src_row, i + 1).as_();
*semisafe_get_mut(dest_row, i) = T::from_u32_or_max_value((a + b + 1) / 2);
}
*semisafe_get_mut(dest_row, width.get() - 1) = *semisafe_get(src_row, width.get() - 1);
offset += pitch.get();
}
}
pub(super) fn refine_vertical_bicubic<T: Pixel>(
dest: &mut [T],
src: &[T],
pitch: NonZeroUsize,
width: NonZeroUsize,
height: NonZeroUsize,
bits_per_sample: NonZeroU8,
) {
let pixel_max = (1u32 << bits_per_sample.get()) - 1;
let mut offset = 0;
for i in 0..width.get() {
let a: u32 = semisafe_get(src, offset + i).as_();
let b: u32 = semisafe_get(src, offset + i + pitch.get()).as_();
*semisafe_get_mut(dest, offset + i) = T::from_u32_or_max_value((a + b + 1) / 2);
}
offset += pitch.get();
for _j in 1..(height.get() - 3) {
for i in 0..width.get() {
let a: i32 = semisafe_get(src, offset + i - pitch.get()).as_();
let b: i32 = semisafe_get(src, offset + i).as_();
let c: i32 = semisafe_get(src, offset + i + pitch.get()).as_();
let d: i32 = semisafe_get(src, offset + i + pitch.get() * 2).as_();
*semisafe_get_mut(dest, offset + i) = T::from_u32_or_max_value(min(
pixel_max,
max(0, (-(a + d) + (b + c) * 9 + 8) >> 4) as u32,
));
}
offset += pitch.get();
}
for _j in (height.get() - 3)..(height.get() - 1) {
for i in 0..width.get() {
let a: u32 = semisafe_get(src, offset + i).as_();
let b: u32 = semisafe_get(src, offset + i + pitch.get()).as_();
*semisafe_get_mut(dest, offset + i) = T::from_u32_or_max_value((a + b + 1) / 2);
}
offset += pitch.get();
}
let dest_row = semisafe_get_mut(semisafe_get_mut(dest, offset..), ..width.get());
let src_row = semisafe_get(semisafe_get(src, offset..), ..width.get());
dest_row.copy_from_slice(src_row);
}