use core::fmt;
use crate::dct53_2d::{
dct8x8_to_dwt53_float_linear, idct8x8_then_dwt53_float, linearized_53_2d_from_plane,
Dwt53TwoDimensional,
};
#[derive(Debug, Clone, PartialEq)]
pub struct Dwt53MultiLevel<T> {
pub levels: Vec<Dwt53TwoDimensional<T>>,
pub final_ll: Vec<T>,
pub final_ll_width: usize,
pub final_ll_height: usize,
}
impl Dwt53MultiLevel<f64> {
#[must_use]
pub fn max_abs_diff(&self, other: &Self) -> f64 {
assert_eq!(self.levels.len(), other.levels.len());
assert_eq!(self.final_ll_width, other.final_ll_width);
assert_eq!(self.final_ll_height, other.final_ll_height);
let level_diff = self
.levels
.iter()
.zip(other.levels.iter())
.map(|(actual, expected)| actual.max_abs_diff(expected))
.fold(0.0, f64::max);
self.final_ll
.iter()
.zip(other.final_ll.iter())
.map(|(actual, expected)| (actual - expected).abs())
.fold(level_diff, f64::max)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Dwt53MultiLevelError {
requested_levels: usize,
available_levels: usize,
}
impl Dwt53MultiLevelError {
#[must_use]
pub const fn requested_levels(self) -> usize {
self.requested_levels
}
#[must_use]
pub const fn available_levels(self) -> usize {
self.available_levels
}
}
impl fmt::Display for Dwt53MultiLevelError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"requested {} decomposition levels, but only {} are available",
self.requested_levels, self.available_levels
)
}
}
impl std::error::Error for Dwt53MultiLevelError {}
pub fn dct8x8_to_dwt53_multilevel_float_linear(
block: [[f64; 8]; 8],
levels: usize,
) -> Result<Dwt53MultiLevel<f64>, Dwt53MultiLevelError> {
validate_levels(levels, 8, 8)?;
Ok(decompose_from_first_level(
dct8x8_to_dwt53_float_linear(block),
levels,
))
}
pub fn idct8x8_then_dwt53_multilevel_float(
block: [[f64; 8]; 8],
levels: usize,
) -> Result<Dwt53MultiLevel<f64>, Dwt53MultiLevelError> {
validate_levels(levels, 8, 8)?;
Ok(decompose_from_first_level(
idct8x8_then_dwt53_float(block),
levels,
))
}
fn decompose_from_first_level(
first_level: Dwt53TwoDimensional<f64>,
levels: usize,
) -> Dwt53MultiLevel<f64> {
let mut decomposition = Dwt53MultiLevel {
final_ll: first_level.ll.clone(),
final_ll_width: first_level.low_width,
final_ll_height: first_level.low_height,
levels: vec![first_level],
};
while decomposition.levels.len() < levels {
let next = linearized_53_2d_from_plane(
&decomposition.final_ll,
decomposition.final_ll_width,
decomposition.final_ll_height,
);
decomposition.final_ll.clone_from(&next.ll);
decomposition.final_ll_width = next.low_width;
decomposition.final_ll_height = next.low_height;
decomposition.levels.push(next);
}
decomposition
}
fn validate_levels(
requested_levels: usize,
width: usize,
height: usize,
) -> Result<(), Dwt53MultiLevelError> {
let available_levels = available_levels(width, height);
if requested_levels == 0 || requested_levels > available_levels {
return Err(Dwt53MultiLevelError {
requested_levels,
available_levels,
});
}
Ok(())
}
fn available_levels(mut width: usize, mut height: usize) -> usize {
let mut levels = 0;
while width >= 2 && height >= 2 {
levels += 1;
width = width.div_ceil(2);
height = height.div_ceil(2);
}
levels
}