// SPDX-License-Identifier: LGPL-2.1 // Copyright 2024 Daniel Vogelbacher // Originally written in C in dcraw.c by Dave Coffin // // Kodak Run Adaptive Differential Coding (RADC) use rayon::iter::IndexedParallelIterator; use rayon::iter::ParallelIterator; use crate::Result; use crate::alloc_image_ok; use crate::bits::LookupTable; use crate::buffer::PaddedBuf; use crate::pixarray::PixU16; use crate::pumps::BitPump; use crate::pumps::BitPumpMSB; #[rustfmt::skip] const HUFF_INIT: [(u8, i8); 130] = [ (1,1), (2,3), (3,4), (4,2), (5,7), (6,5), (7,6), (7,8), (1,0), (2,1), (3,3), (4,4), (5,2), (6,7), (7,6), (8,5), (8,8), (2,1), (2,3), (3,0), (3,2), (3,4), (4,6), (5,5), (6,7), (6,8), (2,0), (2,1), (2,3), (3,2), (4,4), (5,6), (6,7), (7,5), (7,8), (2,1), (2,4), (3,0), (3,2), (3,3), (4,7), (5,5), (6,6), (6,8), (2,3), (3,1), (3,2), (3,4), (3,5), (3,6), (4,7), (5,0), (5,8), (2,3), (2,6), (3,0), (3,1), (4,4), (4,5), (4,7), (5,2), (5,8), (2,4), (2,7), (3,3), (3,6), (4,1), (4,2), (4,5), (5,0), (5,8), (2,6), (3,1), (3,3), (3,5), (3,7), (3,8), (4,0), (5,2), (5,4), (2,0), (2,1), (3,2), (3,3), (4,4), (4,5), (5,6), (5,7), (4,8), (1,0), (2,2), (2,-2), (1,-3), (1,3), (2,-17), (2,-5), (2,5), (2,17), (2,-7), (2,2), (2,9), (2,18), (2,-18), (2,-9), (2,-2), (2,7), (2,-28), (2,28), (3,-49), (3,-9), (3,9), (4,49), (5,-79), (5,79), (2,-1), (2,13), (2,26), (3,39), (4,-16), (5,55), (6,-37), (6,76), (2,-26), (2,-13), (2,1), (3,-39), (4,16), (5,-55), (6,-76), (6,37) ]; #[derive(Default, Clone, Copy, PartialEq, PartialOrd)] struct HuffSymbol { bitcnt: u8, value: u8, } struct HuffDecoder { cache: [[HuffSymbol; 256]; 19], } impl HuffDecoder { /// Create new HuffmanDecoder /// /// cbpp is Compressed Bits Per Pixel fn new(cbpp: u8) -> Self { let mut cache = [[HuffSymbol::default(); 256]; 19]; let mut a = 0; for x in HUFF_INIT { for _ in 0..(256 >> x.0) { // max bit value in cache cache.as_flattened_mut()[a].bitcnt = x.0; cache.as_flattened_mut()[a].value = x.1 as u8; a += 1; } } for c in 0..256 { cache[18][c].bitcnt = 8 - cbpp; cache[18][c].value = ((c as u8) >> cbpp << cbpp) | (1 << (cbpp - 1)); } Self { cache } } #[inline(always)] fn huff_decode(&self, pump: &mut dyn BitPump, tree: usize) -> i8 { let code = pump.peek_bits(8) as usize; let sym = self.cache[tree][code]; pump.consume_bits(sym.bitcnt as u32); sym.value as i8 } } /// Decompress a RADC buffer /// /// cbpp is Compressed Bits Per Pixel pub fn decompress(src: &PaddedBuf, width: usize, height: usize, cbpp: u8, dummy: bool) -> Result { log::debug!("RADC decompress with cbpp: {}, width: {}, height: {}", cbpp, width, height); let mut out = alloc_image_ok!(width, height, dummy); let mut last: [i16; 3] = [16, 16, 16]; let mut mul: [i16; 3]; let mut buf: [[[i16; 386]; 3]; 3] = [[[2048; 386]; 3]; 3]; let tbl = { const PT: [(usize, f32); 6] = [(0, 0.0), (1280, 1344.0), (2320, 3616.0), (3328, 8000.0), (4095, 16383.0), (65535, 16383.0)]; let mut curve = vec![0; 65536]; for i in 1..PT.len() { for c in PT[i - 1].0..=PT[i].0 { curve[c] = ((c - PT[i - 1].0) as f32 / (PT[i].0 - PT[i - 1].0) as f32 * (PT[i].1 - PT[i - 1].1) + PT[i - 1].1 + 0.5) as u16; } } LookupTable::new_with_bits(&curve, 16) }; let dec = HuffDecoder::new(cbpp); let mut pump = BitPumpMSB::new(src); for row in (0..height).step_by(4) { mul = [pump.get_bits(6) as i16, pump.get_bits(6) as i16, pump.get_bits(6) as i16]; for c in 0..3 { let predictor = |buf: &[[[i16; 386]; 3]; 3], x: usize, y: usize| -> i16 { (if c > 0 { (buf[c][y - 1][x] as i32 + buf[c][y][x + 1] as i32) / 2 } else { (buf[c][y - 1][x + 1] as i32 + 2 * buf[c][y - 1][x] as i32 + buf[c][y][x + 1] as i32) / 4 }) as i16 }; let mut val: i32 = ((0x1000000 / (last[c] as i32) + 0x7ff) >> 12) * mul[c] as i32; let s = if val > 65564 { 10 } else { 12 }; let x: i32 = (1 << (s - 1)) - 1; val <<= 12 - s; buf[c].as_flattened_mut().iter_mut().for_each(|i| *i = ((*i as i32 * val + x) >> s) as i16); last[c] = mul[c]; let max = if c == 0 { 1 } else { 0 }; for r in 0..=max { buf[c][1][width / 2] = mul[c] << 7; buf[c][2][width / 2] = mul[c] << 7; let mut tree = 1; let mut col = width / 2; while col > 0 { tree = dec.huff_decode(&mut pump, tree) as usize; if tree != 0 { col -= 2; if tree == 8 { for y in 1..3 { for x in (col..=(col + 1)).rev() { buf[c][y][x] = (dec.huff_decode(&mut pump, 18) as u8) as i16 * mul[c]; assert!(buf[c][y][x] >= 0); } } } else { for y in 1..3 { for x in (col..=(col + 1)).rev() { buf[c][y][x] = dec.huff_decode(&mut pump, tree + 10) as i16 * 16 + predictor(&buf, x, y); } } } } else { loop { let nreps = if col > 2 { dec.huff_decode(&mut pump, 9) + 1 } else { 1 }; for rep in 0..8 { if rep < nreps && col > 0 { col -= 2; for y in 1..3 { for x in (col..=(col + 1)).rev() { buf[c][y][x] = predictor(&buf, x, y); } } if rep & 1 > 0 { let step = dec.huff_decode(&mut pump, 10) << 4; for y in 1..3 { for x in (col..=(col + 1)).rev() { buf[c][y][x] += step as i16; } } } } } if nreps != 9 { break; } } } } for y in 0..2 { for x in 0..(width / 2) { let val = ((buf[c][y + 1][x] as i32) << 4) / mul[c] as i32; let val = if val < 0 { 0 } else { val }; if c > 0 { *out.at_mut(row + y * 2 + c - 1, x * 2 + 2 - c) = val as u16; } else { *out.at_mut(row + r * 2 + y, x * 2 + y) = val as u16; } } } // Copy buffer from buf[c][2] to buf[c][0] // Borrow checker needs this hack... let (dst, src) = buf[c].split_at_mut(2); if c == 0 { dst[0][1..].copy_from_slice(&src[2 - 2][..386 - 1]); } else { dst[0][..].copy_from_slice(&src[2 - 2][..]); } } } for y in row..row + 4 { for x in 0..width { if ((x + y) & 1) > 0 { let r = if x > 0 { x - 1 } else { x + 1 }; let s = if x + 1 < width { x + 1 } else { x - 1 }; let val = (*out.at(y, x) as i32 - 2048) * 2 + ((*out.at(y, r) as i32 + *out.at(y, s) as i32) / 2); if val < 0 { *out.at_mut(y, x) = 0; } else { *out.at_mut(y, x) = val as u16; } } } } } out.par_pixel_rows_mut().enumerate().for_each(|(_row, line)| { let mut random = ((line[0] as u32) << 16) | line[1] as u32; for x in line { *x = tbl.dither(*x, &mut random); } }); Ok(out) }