pub fn gather_dc_symbol(diff: i16, freq: &mut [u32; 257]) {
let category = if diff == 0 {
0u8
} else {
16 - diff.unsigned_abs().leading_zeros() as u8
};
freq[category as usize] += 1;
}
pub fn gather_ac_symbols(coeffs: &[i16; 64], freq: &mut [u32; 257]) {
let mut zero_run: u8 = 0;
for &ac in &coeffs[1..64] {
if ac == 0 {
zero_run += 1;
} else {
while zero_run >= 16 {
freq[0xF0] += 1; zero_run -= 16;
}
let size = 16 - ac.unsigned_abs().leading_zeros() as u8;
let symbol = ((zero_run as u16) << 4) | (size as u16);
freq[symbol as usize] += 1;
zero_run = 0;
}
}
if zero_run > 0 {
freq[0x00] += 1; }
}
pub fn gen_optimal_table(freq: &[u32; 257]) -> ([u8; 17], Vec<u8>) {
let mut symbols: Vec<(u32, usize)> = freq
.iter()
.enumerate()
.filter(|(_, &f)| f > 0)
.map(|(i, &f)| (f, i))
.collect();
if symbols.is_empty() {
return ([0u8; 17], Vec::new());
}
if symbols.len() == 1 {
let dummy = if symbols[0].1 == 0 { 1 } else { 0 };
symbols.push((1, dummy));
}
let n = symbols.len();
symbols.sort_by(|a, b| a.0.cmp(&b.0).then(a.1.cmp(&b.1)));
let mut codesize = vec![0u32; n];
let mut others = vec![-1i32; n];
let mut freqs: Vec<i64> = symbols.iter().map(|(f, _)| *f as i64).collect();
for _ in 0..n - 1 {
let mut v1: i32 = -1;
let mut v2: i32 = -1;
for i in 0..n {
if freqs[i] < 0 {
continue; }
if v1 < 0 || freqs[i] < freqs[v1 as usize] {
v2 = v1;
v1 = i as i32;
} else if v2 < 0 || freqs[i] < freqs[v2 as usize] {
v2 = i as i32;
}
}
if v1 < 0 || v2 < 0 {
break;
}
let v1u = v1 as usize;
let v2u = v2 as usize;
freqs[v1u] += freqs[v2u];
freqs[v2u] = -1;
codesize[v1u] += 1;
let mut c = v1u;
while others[c] >= 0 {
c = others[c] as usize;
codesize[c] += 1;
}
others[c] = v2;
codesize[v2u] += 1;
let mut c = v2u;
while others[c] >= 0 {
c = others[c] as usize;
codesize[c] += 1;
}
}
let mut bits = [0u8; 33]; for &cs_val in &codesize[..n] {
if cs_val > 0 {
let cs = cs_val as usize;
if cs < 33 {
bits[cs] += 1;
}
}
}
let mut max_code_len = 32.min(bits.len() - 1);
while max_code_len > 0 && bits[max_code_len] == 0 {
max_code_len -= 1;
}
while max_code_len > 16 {
let mut j = max_code_len - 2;
while j > 0 && bits[j] == 0 {
j -= 1;
}
bits[max_code_len] -= 2;
bits[max_code_len - 1] += 1;
bits[j + 1] += 2;
bits[j] -= 1;
while max_code_len > 16 && bits[max_code_len] == 0 {
max_code_len -= 1;
}
}
bits[max_code_len] -= 1;
let mut jpeg_bits = [0u8; 17];
let copy_len: usize = 16.min(max_code_len);
jpeg_bits[1..=copy_len].copy_from_slice(&bits[1..=copy_len]);
let mut sym_sizes: Vec<(u32, usize)> = (0..n)
.filter(|&i| codesize[i] > 0 && symbols[i].1 < 256)
.map(|i| (codesize[i], symbols[i].1))
.collect();
sym_sizes.sort_by(|a, b| a.0.cmp(&b.0).then(a.1.cmp(&b.1)));
let huffval: Vec<u8> = sym_sizes.iter().map(|(_, sym)| *sym as u8).collect();
(jpeg_bits, huffval)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gather_dc_zero_diff() {
let mut freq = [0u32; 257];
gather_dc_symbol(0, &mut freq);
assert_eq!(freq[0], 1); }
#[test]
fn gather_dc_positive() {
let mut freq = [0u32; 257];
gather_dc_symbol(5, &mut freq);
assert_eq!(freq[3], 1); }
#[test]
fn gather_dc_negative() {
let mut freq = [0u32; 257];
gather_dc_symbol(-5, &mut freq);
assert_eq!(freq[3], 1); }
#[test]
fn gather_ac_eob() {
let mut freq = [0u32; 257];
let coeffs = [0i16; 64]; gather_ac_symbols(&coeffs, &mut freq);
assert_eq!(freq[0x00], 1); }
#[test]
fn gather_ac_nonzero() {
let mut freq = [0u32; 257];
let mut coeffs = [0i16; 64];
coeffs[1] = 3; gather_ac_symbols(&coeffs, &mut freq);
assert_eq!(freq[0x02], 1);
assert_eq!(freq[0x00], 1); }
#[test]
fn gather_ac_zrl() {
let mut freq = [0u32; 257];
let mut coeffs = [0i16; 64];
coeffs[17] = 1; gather_ac_symbols(&coeffs, &mut freq);
assert_eq!(freq[0xF0], 1); assert_eq!(freq[0x01], 1); assert_eq!(freq[0x00], 1); }
#[test]
fn gen_optimal_table_from_uniform() {
let mut freq = [1u32; 257];
freq[256] = 1; let (bits, values) = gen_optimal_table(&freq);
let total: usize = bits[1..=16].iter().map(|&b| b as usize).sum();
assert!(total <= 256); assert!(total > 0);
assert_eq!(total, values.len());
}
#[test]
fn gen_optimal_table_single_symbol() {
let mut freq = [0u32; 257];
freq[0] = 100;
freq[256] = 1; let (bits, values) = gen_optimal_table(&freq);
let total: usize = bits[1..=16].iter().map(|&b| b as usize).sum();
assert_eq!(total, 1);
assert_eq!(values.len(), 1);
assert_eq!(values[0], 0);
}
#[test]
fn gen_optimal_table_two_symbols() {
let mut freq = [0u32; 257];
freq[0] = 50;
freq[1] = 50;
freq[256] = 1; let (bits, values) = gen_optimal_table(&freq);
let total: usize = bits[1..=16].iter().map(|&b| b as usize).sum();
assert_eq!(total, 2); }
#[test]
fn gen_optimal_table_code_lengths_valid() {
let mut freq = [0u32; 257];
freq[0] = 10000;
for i in 1..20 {
freq[i] = 1;
}
freq[256] = 1;
let (bits, _values) = gen_optimal_table(&freq);
for i in 17..bits.len() {
}
let _ = bits; }
}