1mod linearized53;
4pub use linearized53::{
5 linearized_dwt53_row, Dwt53Band, Dwt53LinearRow, Dwt53LinearTap, DWT53_MAX_HIGH_LINEAR_TAPS,
6 DWT53_MAX_LINEAR_TAPS,
7};
8
9#[must_use]
17pub const fn max_decomposition_levels(width: u32, height: u32) -> u8 {
18 let mut minimum_dimension = if width < height { width } else { height };
19 let mut levels = 0_u8;
20 while minimum_dimension > 1 {
21 minimum_dimension >>= 1;
22 levels += 1;
23 }
24 levels
25}
26
27pub const DWT97_ALPHA_F32: f32 = -1.586_134_3;
29pub const DWT97_BETA_F32: f32 = -0.052_980_117;
31pub const DWT97_GAMMA_F32: f32 = 0.882_911_1;
33pub const DWT97_DELTA_F32: f32 = 0.443_506_87;
35pub const DWT97_KAPPA_F32: f32 = 1.230_174_1;
37pub const DWT97_INV_KAPPA_F32: f32 = 1.0 / DWT97_KAPPA_F32;
39
40pub const IDWT97_NEG_ALPHA_F32: f32 = -DWT97_ALPHA_F32;
42pub const IDWT97_NEG_BETA_F32: f32 = -DWT97_BETA_F32;
44pub const IDWT97_NEG_GAMMA_F32: f32 = -DWT97_GAMMA_F32;
46pub const IDWT97_NEG_DELTA_F32: f32 = -DWT97_DELTA_F32;
48
49pub const DWT97_ALPHA_F64: f64 = -1.586_134_342_059_924;
51pub const DWT97_BETA_F64: f64 = -0.052_980_118_572_961;
53pub const DWT97_GAMMA_F64: f64 = 0.882_911_075_530_934;
55pub const DWT97_DELTA_F64: f64 = 0.443_506_852_043_971;
57pub const DWT97_KAPPA_F64: f64 = 1.230_174_104_914_001;
59pub const DWT97_INV_KAPPA_F64: f64 = 1.0 / DWT97_KAPPA_F64;
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 const MAX_LEVELS_FOR_U32_GEOMETRY: u8 = max_decomposition_levels(u32::MAX, u32::MAX);
67
68 #[test]
69 fn maximum_decomposition_levels_are_const_and_use_the_shorter_axis() {
70 assert_eq!(MAX_LEVELS_FOR_U32_GEOMETRY, 31);
71
72 for (width, height, expected) in [
73 (0, 0, 0),
74 (0, u32::MAX, 0),
75 (u32::MAX, 0, 0),
76 (1, u32::MAX, 0),
77 (u32::MAX, 1, 0),
78 (2, 8, 1),
79 (8, 2, 1),
80 (3, 9, 1),
81 (9, 3, 1),
82 (7, 9, 2),
83 (9, 7, 2),
84 (u32::MAX, u32::MAX, 31),
85 ] {
86 assert_eq!(max_decomposition_levels(width, height), expected);
87 }
88 }
89
90 #[test]
91 fn maximum_decomposition_levels_match_power_of_two_boundaries() {
92 for exponent in 1_u8..=31 {
93 let power = 1_u32 << exponent;
94 assert_eq!(max_decomposition_levels(power, power), exponent);
95 assert_eq!(max_decomposition_levels(power - 1, u32::MAX), exponent - 1);
96 assert_eq!(
97 max_decomposition_levels(power.saturating_add(1), u32::MAX),
98 exponent
99 );
100 }
101 }
102
103 #[test]
104 fn f32_constants_match_existing_backend_rounding() {
105 assert_eq!(DWT97_ALPHA_F32.to_bits(), (-1.586_134_3f32).to_bits());
106 assert_eq!(DWT97_BETA_F32.to_bits(), (-0.052_980_117f32).to_bits());
107 assert_eq!(DWT97_GAMMA_F32.to_bits(), 0.882_911_1f32.to_bits());
108 assert_eq!(DWT97_DELTA_F32.to_bits(), 0.443_506_87f32.to_bits());
109 assert_eq!(DWT97_KAPPA_F32.to_bits(), 1.230_174_1f32.to_bits());
110 assert_eq!(
111 DWT97_INV_KAPPA_F32.to_bits(),
112 (1.0f32 / 1.230_174_1f32).to_bits()
113 );
114 }
115
116 #[test]
117 fn inverse_constants_are_exact_negations_of_forward_steps() {
118 assert_eq!(IDWT97_NEG_ALPHA_F32.to_bits(), (-DWT97_ALPHA_F32).to_bits());
119 assert_eq!(IDWT97_NEG_BETA_F32.to_bits(), (-DWT97_BETA_F32).to_bits());
120 assert_eq!(IDWT97_NEG_GAMMA_F32.to_bits(), (-DWT97_GAMMA_F32).to_bits());
121 assert_eq!(IDWT97_NEG_DELTA_F32.to_bits(), (-DWT97_DELTA_F32).to_bits());
122 }
123}