#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StepSize {
pub exponent: u8,
pub mantissa: u16,
}
impl StepSize {
pub fn to_u16(&self) -> u16 {
((self.exponent as u16) << 11) | (self.mantissa & 0x7FF)
}
pub fn from_u16(val: u16) -> Self {
StepSize {
exponent: (val >> 11) as u8,
mantissa: val & 0x7FF,
}
}
pub fn to_f64(&self) -> f64 {
let base = 1.0 + (self.mantissa as f64) / 2048.0;
base * 2.0_f64.powi(self.exponent as i32)
}
}
static DWT_NORMS: [[f64; 10]; 4] = [
[1.000, 1.500, 2.750, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3],
[1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9, 0.0],
[1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9, 0.0],
[0.7186, 0.9218, 1.586, 3.043, 6.019, 12.01, 24.00, 47.97, 95.93, 0.0],
];
static DWT_NORMS_REAL: [[f64; 10]; 4] = [
[1.000, 1.965, 4.177, 8.403, 16.90, 33.84, 67.69, 135.3, 270.6, 540.9],
[2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0, 0.0],
[2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0, 0.0],
[2.080, 3.865, 8.307, 17.18, 34.71, 69.59, 139.3, 278.6, 557.2, 0.0],
];
static MCT_NORMS: [f64; 3] = [1.732, 0.8292, 0.8292];
static MCT_NORMS_REAL: [f64; 3] = [1.732, 1.805, 1.573];
pub fn dwt_getnorm(level: u32, orient: u32) -> f64 {
let level = if orient == 0 {
level.min(9) as usize
} else {
level.min(8) as usize
};
DWT_NORMS[orient as usize][level]
}
pub fn dwt_getnorm_real(level: u32, orient: u32) -> f64 {
let level = if orient == 0 {
level.min(9) as usize
} else {
level.min(8) as usize
};
DWT_NORMS_REAL[orient as usize][level]
}
pub fn mct_getnorm(compno: u32) -> f64 {
MCT_NORMS[compno as usize]
}
pub fn mct_getnorm_real(compno: u32) -> f64 {
MCT_NORMS_REAL[compno as usize]
}
pub fn quantize_band(coeffs: &mut [i32], stepsize: &StepSize, guard_bits: u8) {
let exp_val = stepsize.exponent as i32 - guard_bits as i32;
let step = (1.0 + stepsize.mantissa as f64 / 2048.0) * 2.0_f64.powi(exp_val);
if step <= 0.0 {
return;
}
for c in coeffs.iter_mut() {
if *c == 0 {
continue;
}
let sign = if *c < 0 { -1 } else { 1 };
let abs_val = (*c as f64).abs();
*c = sign * (abs_val / step).floor() as i32;
}
}
pub fn dequantize_band(coeffs: &mut [i32], stepsize: &StepSize, guard_bits: u8) {
let exp_val = stepsize.exponent as i32 - guard_bits as i32;
let step = (1.0 + stepsize.mantissa as f64 / 2048.0) * 2.0_f64.powi(exp_val);
if step <= 0.0 {
return;
}
for c in coeffs.iter_mut() {
if *c == 0 {
continue;
}
let sign = if *c < 0 { -1.0 } else { 1.0 };
let abs_val = (*c as f64).abs();
let reconstructed = sign * (abs_val + 0.5) * step;
*c = reconstructed.round() as i32;
}
}
pub fn no_quantize(coeffs: &mut [i32], guard_bits: u8) {
if guard_bits == 0 {
return;
}
let shift = guard_bits as u32;
for c in coeffs.iter_mut() {
*c >>= shift;
}
}
fn encode_stepsize(stepsize: i32, numbps: i32) -> StepSize {
let p = floorlog2(stepsize) - 13;
let n = 11 - floorlog2(stepsize);
let mant = if n < 0 {
(stepsize >> (-n)) & 0x7FF
} else {
(stepsize << n) & 0x7FF
};
StepSize {
exponent: (numbps - p) as u8,
mantissa: mant as u16,
}
}
fn floorlog2(mut val: i32) -> i32 {
if val <= 0 {
return 0;
}
let mut result = 0;
while val > 1 {
val >>= 1;
result += 1;
}
result
}
pub fn calc_stepsizes(num_res: u32, prec: u32, is_reversible: bool) -> Vec<StepSize> {
let numbands = 3 * num_res - 2;
let mut stepsizes = Vec::with_capacity(numbands as usize);
for bandno in 0..numbands {
let resno = if bandno == 0 { 0 } else { (bandno - 1) / 3 + 1 };
let orient = if bandno == 0 { 0 } else { (bandno - 1) % 3 + 1 };
let level = num_res - 1 - resno;
let gain: u32 = if !is_reversible {
0
} else if orient == 0 {
0
} else if orient == 1 || orient == 2 {
1
} else {
2
};
let raw_stepsize = if is_reversible {
1.0
} else {
let norm = dwt_getnorm_real(level, orient);
(1u32 << gain) as f64 / norm
};
let encoded = encode_stepsize(
(raw_stepsize * 8192.0).floor() as i32,
(prec + gain) as i32,
);
stepsizes.push(encoded);
}
stepsizes
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stepsize_roundtrip() {
let ss = StepSize {
exponent: 13,
mantissa: 1024,
};
let encoded = ss.to_u16();
let decoded = StepSize::from_u16(encoded);
assert_eq!(ss, decoded);
}
#[test]
fn stepsize_to_f64_basic() {
let ss = StepSize {
exponent: 1,
mantissa: 0,
};
assert!((ss.to_f64() - 2.0).abs() < 1e-10);
}
#[test]
fn quantize_zero() {
let mut coeffs = vec![0, 0, 0];
let ss = StepSize {
exponent: 10,
mantissa: 0,
};
quantize_band(&mut coeffs, &ss, 2);
assert_eq!(coeffs, vec![0, 0, 0]);
}
}