Skip to main content

flashraw_codecs/
kodak.rs

1//! Kodak entropy coders and pixel transforms.
2//!
3//! - **65000** (DCR, DCS Pro / 7x0 series): rows are split into blocks of up to 256
4//!   samples; each block starts with 4-bit difference lengths (two per byte) followed
5//!   by the differences, read LSB-first from big-endian 16-bit words. Predictors reset
6//!   per block (one per column parity). A length nibble above 12 marks a block stored
7//!   as raw 12-bit samples instead. Because a block's byte length follows from its
8//!   length nibbles alone, [`scan_65000_rows`] locates every row cheaply so rows
9//!   decode in parallel.
10//! - **RADC** (DC40/DC50): adaptive Huffman-coded predictive scheme on 4-row bands.
11//! - **DC120**: 8-bit rows stored with a per-row rotation.
12//! - YCbCr 4:2:x to RGB transforms of the C330/C603 compact cameras.
13
14use flashraw_core::bits::{BitPumpMsb, BitRead};
15use flashraw_core::{Error, Result};
16
17/// Samples per 65000 block.
18pub const BLOCK_65000: usize = 256;
19
20/// Byte length of one 65000 block of `len` samples starting at `data[pos..]`, and
21/// whether it is a raw (uncompressed 12-bit) block. `None` if the header is truncated.
22pub fn block_len_65000(data: &[u8], pos: usize, len: usize) -> Option<(usize, bool)> {
23    let bsize = (len + 3) & !3;
24    let hdr = data.get(pos..pos + bsize / 2)?;
25    if hdr.iter().any(|&c| c & 15 > 12 || c >> 4 > 12) {
26        return Some((bsize.div_ceil(8) * 12, true));
27    }
28    let mut consumed = bsize / 2;
29    let mut bits = 0u32;
30    if bsize & 7 == 4 {
31        consumed += 2;
32        bits = 16;
33    }
34    for &c in hdr {
35        for l in [(c & 15) as u32, (c >> 4) as u32] {
36            if bits < l {
37                consumed += 4;
38                bits += 32;
39            }
40            bits -= l;
41        }
42    }
43    Some((consumed, false))
44}
45
46/// Decode one 65000 block of `len` samples at `data[pos..]` into `out` (at least
47/// `(len + 3) & !3` rounded up to 8 entries). Returns `true` for a raw block (values
48/// are absolute samples rather than differences).
49pub fn decode_block_65000(data: &[u8], pos: usize, len: usize, out: &mut [i16]) -> Result<bool> {
50    decode_block_65000_at(data, pos, len, out).map(|(raw, _)| raw)
51}
52
53/// [`decode_block_65000`], also returning the position just past the block (the next
54/// block's start, as [`block_len_65000`] gives it).
55pub fn decode_block_65000_at(data: &[u8], pos: usize, len: usize, out: &mut [i16]) -> Result<(bool, usize)> {
56    let bsize = (len + 3) & !3;
57    let need = bsize.div_ceil(8) * 8;
58    if out.len() < need {
59        return Err(Error::InvalidArgument("Kodak 65000: output block too small".into()));
60    }
61    let hdr = data.get(pos..pos + bsize / 2).ok_or_else(|| Error::corrupt("Kodak 65000: truncated block header"))?;
62    let byte = |p: usize| -> u64 { data.get(p).copied().unwrap_or(0) as u64 };
63    if hdr.iter().any(|&c| c & 15 > 12 || c >> 4 > 12) {
64        // Raw block: groups of six big-endian 16-bit words hold eight 12-bit samples.
65        let mut p = pos;
66        for i in (0..bsize).step_by(8) {
67            let mut raw = [0u16; 6];
68            for r in raw.iter_mut() {
69                *r = ((byte(p) as u16) << 8) | byte(p + 1) as u16;
70                p += 2;
71            }
72            out[i] = (raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12) as i16;
73            out[i + 1] = (raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12) as i16;
74            for j in 0..6 {
75                out[i + 2 + j] = (raw[j] & 0xfff) as i16;
76            }
77        }
78        return Ok((true, p));
79    }
80    let mut p = pos + bsize / 2;
81    let mut bitbuf: u64 = 0;
82    let mut bits = 0u32;
83    if bsize & 7 == 4 {
84        bitbuf = (byte(p) << 8) | byte(p + 1);
85        p += 2;
86        bits = 16;
87    }
88    for i in 0..bsize {
89        let c = hdr[i / 2];
90        let l = if i & 1 == 0 { c & 15 } else { c >> 4 } as u32;
91        if bits < l {
92            // Two big-endian 16-bit words appended above the remaining bits.
93            bitbuf |= ((byte(p) << 8 | byte(p + 1)) | (byte(p + 2) << 8 | byte(p + 3)) << 16) << bits;
94            p += 4;
95            bits += 32;
96        }
97        let mut d = (bitbuf & (0xffff >> (16 - l))) as i32;
98        bitbuf >>= l;
99        bits -= l;
100        if l > 0 && d & (1 << (l - 1)) == 0 {
101            d -= (1 << l) - 1;
102        }
103        out[i] = d as i16;
104    }
105    if p > data.len() + 4 {
106        return Err(Error::corrupt("Kodak 65000: truncated block data"));
107    }
108    Ok((false, p))
109}
110
111/// Locate the start of every row of a 65000 CFA payload of `width x height`
112/// samples starting at `start` (sequential header scan, no entropy decoding).
113pub fn scan_65000_rows(data: &[u8], start: usize, width: usize, height: usize) -> Result<Vec<usize>> {
114    let mut rows = Vec::with_capacity(height);
115    let mut pos = start;
116    for _ in 0..height {
117        rows.push(pos);
118        let mut col = 0;
119        while col < width {
120            let len = BLOCK_65000.min(width - col);
121            let (n, _) =
122                block_len_65000(data, pos, len).ok_or_else(|| Error::corrupt("Kodak 65000: truncated data"))?;
123            pos += n;
124            col += BLOCK_65000;
125        }
126    }
127    Ok(rows)
128}
129
130/// Decode one CFA row of 65000 data starting at `data[pos..]`, mapping values through
131/// `curve` (out-of-range predictions leave the sample at zero). Returns where the next row
132/// starts.
133pub fn decode_65000_row(data: &[u8], mut pos: usize, out: &mut [u16], curve: &[u16]) -> Result<usize> {
134    let width = out.len();
135    let mut buf = [0i16; 272];
136    let mut col = 0;
137    while col < width {
138        let len = BLOCK_65000.min(width - col);
139        if data.get(pos..pos + ((len + 3) & !3) / 2).is_none() {
140            return Err(Error::corrupt("Kodak 65000: truncated data"));
141        }
142        let (raw, end) = decode_block_65000_at(data, pos, len, &mut buf)?;
143        pos = end;
144        let mut pred = [0i32; 2];
145        for (i, o) in out[col..col + len].iter_mut().enumerate() {
146            let idx = if raw {
147                buf[i] as i32
148            } else {
149                pred[i & 1] += buf[i] as i32;
150                pred[i & 1]
151            };
152            if (0..0xffff).contains(&idx) {
153                *o = curve.get(idx as usize).copied().unwrap_or(*curve.last().unwrap_or(&0));
154            }
155        }
156        col += BLOCK_65000;
157    }
158    Ok(pos)
159}
160
161/// DC120: unrotate one 848-byte row.
162pub fn dc120_row(src: &[u8], row: usize, out: &mut [u16]) {
163    const MUL: [usize; 4] = [162, 192, 187, 92];
164    const ADD: [usize; 4] = [0, 636, 424, 212];
165    let shift = row * MUL[row & 3] + ADD[row & 3];
166    let n = src.len();
167    if n == 0 {
168        return;
169    }
170    for (col, o) in out.iter_mut().enumerate() {
171        *o = src[(col + shift) % n] as u16;
172    }
173}
174
175/// Run `f` for the RGB of a Kodak YCbCr triple.
176#[inline(always)]
177fn ycc_rgb(y: i32, cb: i32, cr: i32, curve: &[u16], out: &mut [u16]) {
178    let g = y - ((cb + cr + 2) >> 2);
179    let rgb = [g + cr, g, g + cb];
180    for (o, v) in out.iter_mut().zip(rgb) {
181        *o = curve[v.clamp(0, 255) as usize];
182    }
183}
184
185/// C330: one output row of `width` RGB pixels from a `2 * raw_width`-byte YUYV-like row.
186pub fn c330_row(pixel: &[u8], width: usize, curve: &[u16], out: &mut [u16]) {
187    for col in 0..width {
188        let at = |i: usize| pixel.get(i).copied().unwrap_or(0) as i32;
189        let y = at(col * 2);
190        let cb = at(((col * 2) & !3) | 1) - 128;
191        let cr = at(((col * 2) & !3) | 3) - 128;
192        ycc_rgb(y, cb, cr, curve, &mut out[col * 3..col * 3 + 3]);
193    }
194}
195
196/// C603: one output row from a `3 * width`-byte record holding two luma rows and one
197/// chroma row (`odd` selects the second luma row).
198pub fn c603_row(pixel: &[u8], width: usize, odd: bool, curve: &[u16], out: &mut [u16]) {
199    let at = |i: usize| pixel.get(i).copied().unwrap_or(0) as i32;
200    for col in 0..width {
201        let y = at(width * 2 * odd as usize + col);
202        let cb = at(width + (col & !1)) - 128;
203        let cr = at(width + (col & !1) + 1) - 128;
204        ycc_rgb(y, cb, cr, curve, &mut out[col * 3..col * 3 + 3]);
205    }
206}
207
208/// Inverse transfer table (power `pwr` with a linear toe of slope `ts`, BT.709-style)
209/// over `0..=imax`, used for Kodak compact cameras without a stored curve.
210pub fn gamma_curve(pwr: f64, ts: f64, imax: u32) -> Vec<u16> {
211    let mut g = [pwr, ts, 0.0, 0.0, 0.0, 0.0];
212    let mut bnd = [0.0f64, 0.0];
213    bnd[(g[1] >= 1.0) as usize] = 1.0;
214    if g[1] != 0.0 && (g[1] - 1.0) * (g[0] - 1.0) <= 0.0 {
215        for _ in 0..48 {
216            g[2] = (bnd[0] + bnd[1]) / 2.0;
217            if g[0] != 0.0 {
218                let k = ((g[2] / g[1]).powf(-g[0]) - 1.0) / g[0] - 1.0 / g[2] > -1.0;
219                bnd[k as usize] = g[2];
220            } else {
221                let k = g[2] / (1.0 - 1.0 / g[2]).exp() < g[1];
222                bnd[k as usize] = g[2];
223            }
224        }
225        g[3] = g[2] / g[1];
226        if g[0] != 0.0 {
227            g[4] = g[2] * (1.0 / g[0] - 1.0);
228        }
229    }
230    let mut curve = vec![0xffffu16; 0x10000];
231    for (i, c) in curve.iter_mut().enumerate() {
232        let r = i as f64 / imax as f64;
233        if r < 1.0 {
234            let v = if r < g[2] {
235                r / g[1]
236            } else if g[0] != 0.0 {
237                ((r + g[4]) / (1.0 + g[4])).powf(1.0 / g[0])
238            } else {
239                ((r - 1.0) / g[2]).exp()
240            };
241            *c = (0x10000 as f64 * v) as u16;
242        }
243    }
244    curve
245}
246
247/// RADC (Kodak DC40/DC50): decode `height x width` samples (both at most 512 x 768)
248/// into `out` (row stride `width`). `cbpp` is the EXIF CompressedBitsPerPixel
249/// numerator, which selects the quantisation of the literal-value tree.
250pub fn decode_radc(data: &[u8], width: usize, height: usize, cbpp: u32, out: &mut [u16]) -> Result<()> {
251    const SRC: &[i8] = &[
252        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,
253        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,
254        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,
255        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,
256        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,
257        -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,
258        -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,
259        -13, 2, 1, 3, -39, 4, 16, 5, -55, 6, -76, 6, 37,
260    ];
261    const PT: [i32; 12] = [0, 0, 1280, 1344, 2320, 3616, 3328, 8000, 4095, 16383, 65535, 16383];
262    const COLS: usize = 386;
263    if width > 768 || height > 512 || width < 4 || height % 4 != 0 || out.len() < width * height {
264        return Err(Error::corrupt(format!("RADC: unsupported geometry {width}x{height}")));
265    }
266    // Output curve.
267    let mut curve = vec![0u16; 0x10000];
268    for i in (2..12).step_by(2) {
269        for c in PT[i - 2]..=PT[i] {
270            let v = (c - PT[i - 2]) as f32 / (PT[i] - PT[i - 2]) as f32 * (PT[i + 1] - PT[i - 1]) as f32
271                + PT[i - 1] as f32
272                + 0.5f32;
273            curve[c as usize] = v as u16;
274        }
275    }
276    // Lookup trees: 19 x 256 entries of (length << 8 | value).
277    let mut huff = vec![0u16; 19 * 256];
278    let mut s = 0usize;
279    for pair in SRC.chunks_exact(2) {
280        let n = 256usize >> pair[0];
281        for _ in 0..n {
282            if let Some(h) = huff.get_mut(s) {
283                *h = ((pair[0] as u16) << 8) | (pair[1] as u8 as u16);
284            }
285            s += 1;
286        }
287    }
288    let q = if cbpp == 243 { 2 } else { 3 };
289    for c in 0..256usize {
290        huff[18 * 256 + c] = (((8 - q) as u16) << 8) | ((c >> q << q) | 1 << (q - 1)) as u16;
291    }
292    let mut bits = BitPumpMsb::new(data);
293    let token = |bits: &mut BitPumpMsb, tree: usize| -> i32 {
294        let e = huff[tree * 256 + bits.peek(8) as usize];
295        bits.skip((e >> 8) as u32);
296        (e & 0xff) as u8 as i8 as i32
297    };
298    let mut buf = vec![2048i16; 3 * 3 * COLS];
299    let at = |c: usize, y: usize, x: usize| (c * 3 + y) * COLS + x;
300    let mut last = [16i32; 3];
301    let half = width / 2;
302    let raw = |out: &mut [u16], r: usize, x: usize, v: i32| {
303        if let Some(o) = out.get_mut(r * width + x) {
304            *o = v as u16;
305        }
306    };
307    for row in (0..height).step_by(4) {
308        let mut mul = [0i32; 3];
309        for m in mul.iter_mut() {
310            *m = bits.get(6) as i32;
311        }
312        if mul.contains(&0) {
313            return Err(Error::corrupt("RADC: zero multiplier"));
314        }
315        for c in 0..3 {
316            let mut val = ((0x100_0000 / last[c] + 0x7ff) >> 12) * mul[c];
317            let s = if val > 65564 { 10 } else { 12 };
318            let x = (1i64 << (s - 1)) - 1;
319            val <<= 12 - s;
320            for e in buf[c * 3 * COLS..(c + 1) * 3 * COLS].iter_mut() {
321                *e = ((((*e as i64) * val as i64 + x).min(0x7FFF_FFFF) >> s) & 0xffff) as u16 as i16;
322            }
323            last[c] = mul[c];
324            let pred = |buf: &[i16], y: usize, x: usize| -> i32 {
325                if c != 0 {
326                    (buf[at(c, y - 1, x)] as i32 + buf[at(c, y, x + 1)] as i32) / 2
327                } else {
328                    (buf[at(c, y - 1, x + 1)] as i32 + 2 * buf[at(c, y - 1, x)] as i32 + buf[at(c, y, x + 1)] as i32)
329                        / 4
330                }
331            };
332            for r in 0..=(c == 0) as usize {
333                let v = (mul[c] << 7) as i16;
334                buf[at(c, 1, half)] = v;
335                buf[at(c, 2, half)] = v;
336                let mut tree = 1usize;
337                let mut col = half as i32;
338                let mut guard = 0usize;
339                while col > 0 {
340                    guard += 1;
341                    if guard > 4 * width || bits.exhausted() {
342                        return Err(Error::corrupt("RADC: truncated data"));
343                    }
344                    let t = token(&mut bits, tree);
345                    if !(0..=8).contains(&t) {
346                        return Err(Error::corrupt("RADC: invalid tree token"));
347                    }
348                    tree = t as usize;
349                    if tree != 0 {
350                        col -= 2;
351                        if col >= 0 {
352                            for y in 1..3 {
353                                for x in [col as usize + 1, col as usize] {
354                                    let nv = if tree == 8 {
355                                        (token(&mut bits, 18) as u8 as i32) * mul[c]
356                                    } else {
357                                        token(&mut bits, tree + 10) * 16 + pred(&buf, y, x)
358                                    };
359                                    buf[at(c, y, x)] = nv as i16;
360                                }
361                            }
362                        }
363                    } else {
364                        loop {
365                            let nreps = if col > 2 { token(&mut bits, 9) + 1 } else { 1 };
366                            let mut rep = 0;
367                            while rep < 8 && rep < nreps && col > 0 {
368                                col -= 2;
369                                if col >= 0 {
370                                    for y in 1..3 {
371                                        for x in [col as usize + 1, col as usize] {
372                                            buf[at(c, y, x)] = pred(&buf, y, x) as i16;
373                                        }
374                                    }
375                                }
376                                if rep & 1 != 0 {
377                                    let step = token(&mut bits, 10) << 4;
378                                    for y in 1..3 {
379                                        for x in [col.max(0) as usize + 1, col.max(0) as usize] {
380                                            if col >= 0 {
381                                                let e = &mut buf[at(c, y, x)];
382                                                *e = e.wrapping_add(step as i16);
383                                            }
384                                        }
385                                    }
386                                }
387                                rep += 1;
388                            }
389                            if nreps != 9 {
390                                break;
391                            }
392                        }
393                    }
394                }
395                for y in 0..2 {
396                    for x in 0..half {
397                        let v = ((buf[at(c, y + 1, x)] as i32) << 4) / mul[c];
398                        let v = v.max(0);
399                        if c != 0 {
400                            raw(out, row + y * 2 + c - 1, x * 2 + 2 - c, v);
401                        } else {
402                            raw(out, row + r * 2 + y, x * 2 + y, v);
403                        }
404                    }
405                }
406                // Row 2 becomes row 0 (shifted by one for luma).
407                let skip = (c == 0) as usize;
408                let (dst, src) = (at(c, 0, 0), at(c, 2, 0));
409                let tmp: Vec<i16> = buf[src..src + COLS - skip].to_vec();
410                buf[dst + skip..dst + COLS].copy_from_slice(&tmp);
411            }
412        }
413        for y in row..row + 4 {
414            for x in 0..width {
415                if (x + y) & 1 == 1 {
416                    let r = if x > 0 { x - 1 } else { x + 1 };
417                    let s = if x + 1 < width { x + 1 } else { x - 1 };
418                    let g = |xx: usize| out[y * width + xx] as i32;
419                    let v = ((g(x) - 2048) * 2 + (g(r) + g(s)) / 2).max(0);
420                    out[y * width + x] = v as u16;
421                }
422            }
423        }
424    }
425    for v in out[..width * height].iter_mut() {
426        *v = curve[*v as usize];
427    }
428    Ok(())
429}
430
431#[cfg(test)]
432mod tests {
433    use super::*;
434
435    /// Encode a 65000 block (lengths + LSB-first diffs in BE 16-bit words).
436    fn encode_block(diffs: &[i32]) -> Vec<u8> {
437        let bsize = (diffs.len() + 3) & !3;
438        let mut d = diffs.to_vec();
439        d.resize(bsize, 0);
440        let lens: Vec<u32> =
441            d.iter().map(|&v| if v == 0 { 0 } else { 32 - v.unsigned_abs().leading_zeros() }).collect();
442        let mut out: Vec<u8> = lens.chunks(2).map(|p| (p[0] | p[1] << 4) as u8).collect();
443        // Bit stream: values LSB-first; serialise as BE 16-bit words, with the special
444        // 2-byte prefix when bsize % 8 == 4.
445        let mut bits: Vec<u8> = Vec::new();
446        for (i, &v) in d.iter().enumerate() {
447            let l = lens[i];
448            let code = if v >= 0 { v as u32 } else { (v + (1 << l) - 1) as u32 };
449            for b in 0..l {
450                bits.push(((code >> b) & 1) as u8);
451            }
452        }
453        let mut words: Vec<u16> = Vec::new();
454        for chunk in bits.chunks(16) {
455            let mut w = 0u16;
456            for (k, &b) in chunk.iter().enumerate() {
457                w |= (b as u16) << k;
458            }
459            words.push(w);
460        }
461        // Mimic the decoder's fetch granularity: emit enough words (pad to word pairs).
462        words.resize(words.len() + 4, 0);
463        for w in words {
464            out.extend(w.to_be_bytes());
465        }
466        out
467    }
468
469    #[test]
470    fn block_65000_round_trip() {
471        for n in [256usize, 100, 8, 4, 3] {
472            let diffs: Vec<i32> = (0..n).map(|i| ((i as i32 * 37) % 201) - 100).collect();
473            let data = encode_block(&diffs);
474            let mut out = [0i16; 272];
475            let raw = decode_block_65000(&data, 0, n, &mut out).unwrap();
476            assert!(!raw);
477            assert_eq!(&out[..n].iter().map(|&v| v as i32).collect::<Vec<_>>(), &diffs);
478        }
479    }
480
481    #[test]
482    fn raw_block_and_lengths() {
483        // A header nibble of 15 selects raw mode; 8 samples from 12 bytes.
484        let mut data = vec![0xFFu8; 12];
485        data[0] = 0x1A;
486        data[1] = 0xBC;
487        let mut out = [0i16; 16];
488        assert!(decode_block_65000(&data, 0, 8, &mut out).unwrap());
489        assert_eq!(out[2], 0xABC);
490        assert_eq!(block_len_65000(&data, 0, 8), Some((12, true)));
491    }
492
493    #[test]
494    fn dc120_rotation() {
495        let src: Vec<u8> = (0..848u32).map(|i| (i % 251) as u8).collect();
496        let mut out = vec![0u16; 848];
497        dc120_row(&src, 1, &mut out);
498        assert_eq!(out[0], src[192 + 636] as u16);
499    }
500
501    #[test]
502    fn gamma_curve_monotonic() {
503        let c = gamma_curve(0.0, 3.875, 255);
504        assert_eq!(c[0], 0);
505        assert!(c.windows(2).take(255).all(|w| w[0] <= w[1]));
506        assert_eq!(c[255], 0xffff);
507    }
508
509    #[test]
510    fn radc_garbage_no_panic() {
511        let mut seed = 1u32;
512        let data: Vec<u8> = (0..5000)
513            .map(|_| {
514                seed = seed.wrapping_mul(1664525).wrapping_add(1013904223);
515                (seed >> 24) as u8 | 1
516            })
517            .collect();
518        let mut out = vec![0u16; 768 * 512];
519        let _ = decode_radc(&data, 768, 512, 152, &mut out);
520        assert!(decode_radc(&data, 1000, 512, 152, &mut out).is_err());
521    }
522}