pub const PROGRESSIVE_ZIGZAG: [u8; 64] = [
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20,
13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
];
pub const ALTERNATE_ZIGZAG: [u8; 64] = [
0, 8, 1, 9, 16, 24, 17, 2, 10, 18, 25, 32, 40, 33, 26, 19, 11, 3, 4, 12, 20, 27, 34, 41, 48,
56, 49, 42, 35, 28, 21, 13, 5, 6, 14, 22, 29, 36, 43, 50, 57, 58, 51, 44, 37, 30, 23, 15, 7,
31, 38, 45, 52, 59, 60, 53, 46, 39, 47, 54, 61, 62, 55, 63,
];
#[must_use]
pub fn inverse_scan(coeffs_in_scan_order: &[i32; 64], scan_table: &[u8; 64]) -> [i32; 64] {
let mut out = [0i32; 64];
for (scan_idx, &raster_idx) in scan_table.iter().enumerate() {
out[raster_idx as usize] = coeffs_in_scan_order[scan_idx];
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn progressive_zigzag_is_a_permutation() {
let mut seen = [false; 64];
for &raster in &PROGRESSIVE_ZIGZAG {
assert!(raster < 64);
assert!(!seen[raster as usize], "duplicate raster index {raster}");
seen[raster as usize] = true;
}
assert!(seen.iter().all(|s| *s));
}
#[test]
fn alternate_zigzag_is_a_permutation() {
let mut seen = [false; 64];
for &raster in &ALTERNATE_ZIGZAG {
assert!(raster < 64);
assert!(!seen[raster as usize], "duplicate raster index {raster}");
seen[raster as usize] = true;
}
assert!(seen.iter().all(|s| *s));
}
#[test]
fn dc_lives_at_index_zero_in_both_scans() {
assert_eq!(PROGRESSIVE_ZIGZAG[0], 0);
assert_eq!(ALTERNATE_ZIGZAG[0], 0);
}
#[test]
fn highest_frequency_at_end_of_progressive_scan() {
assert_eq!(PROGRESSIVE_ZIGZAG[63], 63);
}
#[test]
fn inverse_scan_dc_only_block() {
let mut scan = [0i32; 64];
scan[0] = 42;
let raster = inverse_scan(&scan, &PROGRESSIVE_ZIGZAG);
assert_eq!(raster[0], 42);
assert!(raster[1..].iter().all(|&v| v == 0));
}
#[test]
fn inverse_scan_round_trip_identity() {
let raster: [i32; 64] = std::array::from_fn(|i| i as i32);
let mut scan = [0i32; 64];
for (scan_idx, &raster_idx) in PROGRESSIVE_ZIGZAG.iter().enumerate() {
scan[scan_idx] = raster[raster_idx as usize];
}
let back = inverse_scan(&scan, &PROGRESSIVE_ZIGZAG);
assert_eq!(back, raster);
}
}