Skip to main content

oximedia_codec/webp/
vp8l_decoder.rs

1//! VP8L (WebP lossless) decoder.
2//!
3//! Implements the VP8L lossless bitstream specification for decoding
4//! WebP lossless images. VP8L uses Huffman coding, LZ77 backward
5//! references, a color cache, and spatial prediction transforms.
6//!
7//! Reference: <https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification>
8
9use crate::error::{CodecError, CodecResult};
10
11/// VP8L signature byte.
12const VP8L_SIGNATURE: u8 = 0x2F;
13
14/// Maximum image dimension (14 bits + 1).
15const MAX_DIMENSION: u32 = 16384;
16
17/// Maximum number of Huffman code groups.
18const MAX_HUFFMAN_GROUPS: usize = 256 * 256;
19
20/// Maximum color cache bits.
21const MAX_COLOR_CACHE_BITS: u32 = 11;
22
23/// Number of literal codes (ARGB channels each 0-255).
24const NUM_LITERAL_CODES: u16 = 256;
25
26/// Number of length prefix codes.
27const NUM_LENGTH_CODES: u16 = 24;
28
29/// Number of distance prefix codes.
30const NUM_DISTANCE_CODES: u16 = 40;
31
32/// Maximum Huffman code length.
33const MAX_ALLOWED_CODE_LENGTH: u8 = 15;
34
35/// Order in which code length code lengths are stored.
36const CODE_LENGTH_CODE_ORDER: [u8; 19] = [
37    17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
38];
39
40/// Number of code length codes.
41const NUM_CODE_LENGTH_CODES: usize = 19;
42
43/// VP8L 2-D distance mapping table (120 entries as (dx, dy) pairs).
44const DISTANCE_MAP: [(i8, i8); 120] = [
45    (0, 1),
46    (1, 0),
47    (1, 1),
48    (-1, 1),
49    (0, 2),
50    (2, 0),
51    (1, 2),
52    (-1, 2),
53    (2, 1),
54    (-2, 1),
55    (2, 2),
56    (-2, 2),
57    (0, 3),
58    (3, 0),
59    (1, 3),
60    (-1, 3),
61    (3, 1),
62    (-3, 1),
63    (2, 3),
64    (-2, 3),
65    (3, 2),
66    (-3, 2),
67    (0, 4),
68    (4, 0),
69    (1, 4),
70    (-1, 4),
71    (4, 1),
72    (-4, 1),
73    (3, 3),
74    (-3, 3),
75    (2, 4),
76    (-2, 4),
77    (4, 2),
78    (-4, 2),
79    (0, 5),
80    (3, 4),
81    (-3, 4),
82    (4, 3),
83    (-4, 3),
84    (5, 0),
85    (1, 5),
86    (-1, 5),
87    (5, 1),
88    (-5, 1),
89    (2, 5),
90    (-2, 5),
91    (5, 2),
92    (-5, 2),
93    (4, 4),
94    (-4, 4),
95    (3, 5),
96    (-3, 5),
97    (5, 3),
98    (-5, 3),
99    (0, 6),
100    (6, 0),
101    (1, 6),
102    (-1, 6),
103    (6, 1),
104    (-6, 1),
105    (2, 6),
106    (-2, 6),
107    (6, 2),
108    (-6, 2),
109    (4, 5),
110    (-4, 5),
111    (5, 4),
112    (-5, 4),
113    (3, 6),
114    (-3, 6),
115    (6, 3),
116    (-6, 3),
117    (0, 7),
118    (7, 0),
119    (1, 7),
120    (-1, 7),
121    (5, 5),
122    (-5, 5),
123    (7, 1),
124    (-7, 1),
125    (4, 6),
126    (-4, 6),
127    (6, 4),
128    (-6, 4),
129    (2, 7),
130    (-2, 7),
131    (7, 2),
132    (-7, 2),
133    (3, 7),
134    (-3, 7),
135    (7, 3),
136    (-7, 3),
137    (5, 6),
138    (-5, 6),
139    (6, 5),
140    (-6, 5),
141    (8, 0),
142    (4, 7),
143    (-4, 7),
144    (7, 4),
145    (-7, 4),
146    (8, 1),
147    (8, 2),
148    (6, 6),
149    (-6, 6),
150    (8, 3),
151    (5, 7),
152    (-5, 7),
153    (7, 5),
154    (-7, 5),
155    (8, 4),
156    (6, 7),
157    (-6, 7),
158    (7, 6),
159    (-7, 6),
160    (8, 5),
161    (7, 7),
162    (-7, 7),
163    (8, 6),
164    (8, 7),
165];
166
167/// VP8L bitstream header.
168#[derive(Debug, Clone)]
169pub struct Vp8lHeader {
170    /// Image width in pixels.
171    pub width: u32,
172    /// Image height in pixels.
173    pub height: u32,
174    /// Whether the image contains non-opaque alpha values.
175    pub alpha_is_used: bool,
176    /// Version number (must be 0).
177    pub version: u8,
178}
179
180impl Vp8lHeader {
181    /// Parse a VP8L header from data starting at the signature byte.
182    pub fn parse(data: &[u8]) -> CodecResult<Self> {
183        if data.len() < 5 {
184            return Err(CodecError::InvalidBitstream("VP8L header too short".into()));
185        }
186        if data[0] != VP8L_SIGNATURE {
187            return Err(CodecError::InvalidBitstream(format!(
188                "Invalid VP8L signature: 0x{:02X}",
189                data[0]
190            )));
191        }
192        // 32 bits packed little-endian: width-1(14) | height-1(14) | alpha(1) | version(3)
193        let val = u32::from(data[1])
194            | (u32::from(data[2]) << 8)
195            | (u32::from(data[3]) << 16)
196            | (u32::from(data[4]) << 24);
197
198        let width = (val & 0x3FFF) + 1;
199        let height = ((val >> 14) & 0x3FFF) + 1;
200        let alpha_is_used = ((val >> 28) & 1) != 0;
201        let version = ((val >> 29) & 0x7) as u8;
202
203        if version != 0 {
204            return Err(CodecError::InvalidBitstream(format!(
205                "Unsupported VP8L version: {version}"
206            )));
207        }
208        if width > MAX_DIMENSION || height > MAX_DIMENSION {
209            return Err(CodecError::InvalidBitstream(format!(
210                "Image dimensions too large: {width}x{height}"
211            )));
212        }
213
214        Ok(Self {
215            width,
216            height,
217            alpha_is_used,
218            version,
219        })
220    }
221}
222
223// Bit Reader (LSB-first)
224
225/// LSB-first bit reader for VP8L bitstreams.
226pub struct Vp8lBitReader<'a> {
227    data: &'a [u8],
228    pos: usize,
229    bit_pos: u32,
230    value: u64,
231    bits_in_value: u32,
232}
233
234impl<'a> Vp8lBitReader<'a> {
235    /// Create a new bit reader starting at the given data.
236    pub fn new(data: &'a [u8]) -> Self {
237        let mut reader = Self {
238            data,
239            pos: 0,
240            bit_pos: 0,
241            value: 0,
242            bits_in_value: 0,
243        };
244        reader.fill();
245        reader
246    }
247
248    /// Fill the value register with bytes from the stream.
249    fn fill(&mut self) {
250        while self.bits_in_value < 56 && self.pos < self.data.len() {
251            self.value |= u64::from(self.data[self.pos]) << self.bits_in_value;
252            self.pos += 1;
253            self.bits_in_value += 8;
254        }
255    }
256
257    /// Read `n` bits (LSB-first) and return them as a `u32`.
258    pub fn read_bits(&mut self, n: u32) -> CodecResult<u32> {
259        if n == 0 {
260            return Ok(0);
261        }
262        if n > 32 {
263            return Err(CodecError::InvalidBitstream(
264                "Cannot read more than 32 bits at once".into(),
265            ));
266        }
267        if self.bits_in_value < n {
268            self.fill();
269        }
270        if self.bits_in_value < n {
271            return Err(CodecError::NeedMoreData);
272        }
273        let mask = if n == 32 { u32::MAX } else { (1u32 << n) - 1 };
274        let result = (self.value as u32) & mask;
275        self.value >>= n;
276        self.bits_in_value -= n;
277        self.bit_pos += n;
278        Ok(result)
279    }
280
281    /// Read a single bit.
282    #[inline]
283    pub fn read_bit(&mut self) -> CodecResult<bool> {
284        Ok(self.read_bits(1)? != 0)
285    }
286
287    /// Peek at the next `n` bits without consuming them.
288    pub fn peek_bits(&mut self, n: u32) -> CodecResult<u32> {
289        if n == 0 {
290            return Ok(0);
291        }
292        if self.bits_in_value < n {
293            self.fill();
294        }
295        if self.bits_in_value < n {
296            return Err(CodecError::NeedMoreData);
297        }
298        let mask = if n == 32 { u32::MAX } else { (1u32 << n) - 1 };
299        Ok((self.value as u32) & mask)
300    }
301
302    /// Advance past `n` bits (used after peeking).
303    pub fn advance(&mut self, n: u32) {
304        self.value >>= n;
305        self.bits_in_value = self.bits_in_value.saturating_sub(n);
306        self.bit_pos += n;
307    }
308}
309
310// Huffman Tree
311
312/// A single entry in a Huffman lookup table.
313#[derive(Debug, Clone, Copy, Default)]
314pub struct HuffmanCode {
315    /// Number of bits for this code.
316    pub bits: u8,
317    /// Symbol value.
318    pub value: u16,
319}
320
321/// Huffman tree built from canonical code lengths.
322#[derive(Debug, Clone)]
323pub struct HuffmanTree {
324    /// Flat lookup table (two-level for long codes).
325    lut: Vec<HuffmanCode>,
326    /// First-level table bits.
327    lut_bits: u8,
328    /// Second-level tables (offset, bits) indexed by first-level sentinel.
329    second_level: Vec<(usize, u8)>,
330    /// Second-level storage.
331    lut2: Vec<HuffmanCode>,
332}
333
334impl HuffmanTree {
335    /// Build a Huffman tree from an array of code lengths.
336    fn build(code_lengths: &[u8], alphabet_size: u16) -> CodecResult<Self> {
337        let max_len = code_lengths.iter().copied().max().unwrap_or(0);
338        if max_len == 0 {
339            // All zero code lengths – treat as single symbol 0.
340            let mut lut = vec![HuffmanCode::default(); 1];
341            lut[0] = HuffmanCode { bits: 0, value: 0 };
342            return Ok(Self {
343                lut,
344                lut_bits: 0,
345                second_level: Vec::new(),
346                lut2: Vec::new(),
347            });
348        }
349
350        let lut_bits = max_len.min(8);
351        let table_size = 1usize << lut_bits;
352        let mut lut = vec![HuffmanCode::default(); table_size];
353
354        // Count per length.
355        let mut bl_count = vec![0u32; (max_len as usize) + 1];
356        for &cl in code_lengths.iter().take(alphabet_size as usize) {
357            if cl > 0 {
358                bl_count[cl as usize] += 1;
359            }
360        }
361
362        // Compute next_code.
363        let mut next_code = vec![0u32; (max_len as usize) + 1];
364        {
365            let mut code: u32 = 0;
366            for bits in 1..=max_len as usize {
367                code = (code + bl_count[bits - 1]) << 1;
368                next_code[bits] = code;
369            }
370        }
371
372        // Assign codes to symbols.
373        let mut codes = Vec::with_capacity(alphabet_size as usize);
374        for symbol in 0..alphabet_size {
375            let cl = if (symbol as usize) < code_lengths.len() {
376                code_lengths[symbol as usize]
377            } else {
378                0
379            };
380            if cl > 0 {
381                let c = next_code[cl as usize];
382                next_code[cl as usize] += 1;
383                codes.push((symbol, cl, c));
384            }
385        }
386
387        // Populate first-level table.
388        let mut second_level = Vec::new();
389        let mut lut2 = Vec::new();
390
391        for &(symbol, cl, code) in &codes {
392            if cl <= lut_bits {
393                // Fits in the first-level table – replicate.
394                let rev = reverse_bits(code, cl);
395                let step = 1u32 << cl;
396                let mut idx = rev;
397                while idx < table_size as u32 {
398                    lut[idx as usize] = HuffmanCode {
399                        bits: cl,
400                        value: symbol,
401                    };
402                    idx += step;
403                }
404            }
405        }
406
407        // Second-level tables for codes longer than lut_bits.
408        if max_len > lut_bits {
409            // Mark first-level entries that need second level.
410            // Group by their first lut_bits.
411            let mut max_second_bits: Vec<u8> = vec![0; table_size];
412            for &(_symbol, cl, code) in &codes {
413                if cl > lut_bits {
414                    let rev = reverse_bits(code, cl);
415                    let idx = rev & ((1u32 << lut_bits) - 1);
416                    let remaining = cl - lut_bits;
417                    if remaining > max_second_bits[idx as usize] {
418                        max_second_bits[idx as usize] = remaining;
419                    }
420                }
421            }
422
423            // Allocate second-level tables.
424            for first_idx in 0..table_size {
425                let sb = max_second_bits[first_idx];
426                if sb > 0 {
427                    let offset = lut2.len();
428                    let size2 = 1usize << sb;
429                    lut2.resize(lut2.len() + size2, HuffmanCode::default());
430                    // Store mapping: sentinel in first-level.
431                    let sl_index = second_level.len();
432                    second_level.push((offset, sb));
433                    lut[first_idx] = HuffmanCode {
434                        bits: lut_bits + sb, // sentinel
435                        value: sl_index as u16,
436                    };
437                }
438            }
439
440            // Fill second-level entries.
441            for &(symbol, cl, code) in &codes {
442                if cl > lut_bits {
443                    let rev = reverse_bits(code, cl);
444                    let first_idx = (rev & ((1u32 << lut_bits) - 1)) as usize;
445                    let entry = &lut[first_idx];
446                    let sl_index = entry.value as usize;
447                    let (offset, sb) = second_level[sl_index];
448                    let remaining = cl - lut_bits;
449                    let rev2 = rev >> lut_bits;
450                    let step = 1u32 << remaining;
451                    let mut idx = rev2;
452                    while idx < (1u32 << sb) {
453                        lut2[offset + idx as usize] = HuffmanCode {
454                            bits: cl,
455                            value: symbol,
456                        };
457                        idx += step;
458                    }
459                }
460            }
461        }
462
463        Ok(Self {
464            lut,
465            lut_bits,
466            second_level,
467            lut2,
468        })
469    }
470
471    /// Decode a single symbol from the bit reader.
472    fn read_symbol(&self, br: &mut Vp8lBitReader<'_>) -> CodecResult<u16> {
473        if self.lut_bits == 0 {
474            // Single-symbol tree.
475            return Ok(self.lut.first().map_or(0, |c| c.value));
476        }
477        let peek = br.peek_bits(u32::from(self.lut_bits))?;
478        let entry = self.lut[peek as usize];
479
480        if entry.bits <= self.lut_bits {
481            br.advance(u32::from(entry.bits));
482            Ok(entry.value)
483        } else {
484            // Second-level lookup.
485            let sl_index = entry.value as usize;
486            if sl_index >= self.second_level.len() {
487                return Err(CodecError::InvalidBitstream(
488                    "Invalid Huffman second-level index".into(),
489                ));
490            }
491            let (offset, sb) = self.second_level[sl_index];
492            let total_bits = self.lut_bits + sb;
493            let peek2 = br.peek_bits(u32::from(total_bits))?;
494            let idx2 = (peek2 >> self.lut_bits) as usize;
495            if offset + idx2 >= self.lut2.len() {
496                return Err(CodecError::InvalidBitstream(
497                    "Huffman second-level table overflow".into(),
498                ));
499            }
500            let entry2 = self.lut2[offset + idx2];
501            br.advance(u32::from(entry2.bits));
502            Ok(entry2.value)
503        }
504    }
505}
506
507/// Reverse the bottom `n` bits of `val`.
508fn reverse_bits(val: u32, n: u8) -> u32 {
509    let mut result = 0u32;
510    let mut v = val;
511    for _ in 0..n {
512        result = (result << 1) | (v & 1);
513        v >>= 1;
514    }
515    result
516}
517
518// Huffman Group (5 trees)
519
520/// A group of five Huffman trees used for decoding one region.
521#[derive(Debug, Clone)]
522struct HuffmanGroup {
523    /// Green + length + color cache codes.
524    green: HuffmanTree,
525    /// Red channel codes.
526    red: HuffmanTree,
527    /// Blue channel codes.
528    blue: HuffmanTree,
529    /// Alpha channel codes.
530    alpha: HuffmanTree,
531    /// Distance prefix codes.
532    distance: HuffmanTree,
533}
534
535// Transforms
536
537/// VP8L image transform.
538#[derive(Debug, Clone)]
539pub enum Transform {
540    /// Spatial prediction transform.
541    Predictor {
542        /// Log2 of block size minus 2.
543        size_bits: u8,
544        /// Sub-resolution predictor image (ARGB pixels).
545        data: Vec<u32>,
546    },
547    /// Color decorrelation transform.
548    ColorTransform {
549        /// Log2 of block size minus 2.
550        size_bits: u8,
551        /// Color transform elements per block.
552        data: Vec<ColorTransformElement>,
553    },
554    /// Subtract green transform (no data).
555    SubtractGreen,
556    /// Color indexing (palette) transform.
557    ColorIndexing {
558        /// Palette colors (ARGB).
559        palette: Vec<u32>,
560        /// Bits per pixel index (1, 2, 4, or 8).
561        bits_per_pixel: u8,
562    },
563}
564
565/// Color transform element used for decorrelation.
566#[derive(Debug, Clone, Copy, Default)]
567pub struct ColorTransformElement {
568    /// Green-to-red multiplier.
569    pub green_to_red: i8,
570    /// Green-to-blue multiplier.
571    pub green_to_blue: i8,
572    /// Red-to-blue multiplier.
573    pub red_to_blue: i8,
574}
575
576// Color Cache
577
578/// Color cache for VP8L decoding.
579struct ColorCache {
580    colors: Vec<u32>,
581    hash_shift: u32,
582}
583
584impl ColorCache {
585    fn new(bits: u32) -> Self {
586        let size = 1usize << bits;
587        Self {
588            colors: vec![0u32; size],
589            hash_shift: 32 - bits,
590        }
591    }
592
593    fn lookup(&self, index: u32) -> u32 {
594        self.colors[index as usize & (self.colors.len() - 1)]
595    }
596
597    fn insert(&mut self, argb: u32) {
598        let hash = (0x1E35_A7BDu64.wrapping_mul(u64::from(argb)) >> self.hash_shift) as usize;
599        let len = self.colors.len();
600        self.colors[hash & (len - 1)] = argb;
601    }
602}
603
604// Decoded Image
605
606/// Result of VP8L decoding.
607pub struct DecodedImage {
608    /// Image width in pixels.
609    pub width: u32,
610    /// Image height in pixels.
611    pub height: u32,
612    /// ARGB pixel data (row-major, `width * height` elements).
613    pub pixels: Vec<u32>,
614    /// Whether the image contains non-opaque alpha.
615    pub has_alpha: bool,
616}
617
618// VP8L Decoder
619
620/// VP8L lossless image decoder.
621pub struct Vp8lDecoder {
622    width: u32,
623    height: u32,
624    alpha_is_used: bool,
625    transforms: Vec<Transform>,
626}
627
628impl Vp8lDecoder {
629    /// Create a new decoder (dimensions set during `decode`).
630    pub fn new() -> Self {
631        Self {
632            width: 0,
633            height: 0,
634            alpha_is_used: false,
635            transforms: Vec::new(),
636        }
637    }
638
639    /// Decode a VP8L bitstream starting at the signature byte.
640    pub fn decode(&mut self, data: &[u8]) -> CodecResult<DecodedImage> {
641        let header = Vp8lHeader::parse(data)?;
642        self.width = header.width;
643        self.height = header.height;
644        self.alpha_is_used = header.alpha_is_used;
645        self.transforms.clear();
646
647        // Bit reader starts after the 5-byte header.
648        let mut br = Vp8lBitReader::new(&data[5..]);
649
650        // Read transforms.
651        let (decoded_width, decoded_height) = self.read_transforms(&mut br)?;
652
653        // Decode the main image.
654        let pixels = self.decode_image_data(&mut br, decoded_width, decoded_height)?;
655
656        // Apply transforms in reverse order.
657        let pixels = self.apply_transforms(pixels, decoded_width, decoded_height)?;
658
659        Ok(DecodedImage {
660            width: self.width,
661            height: self.height,
662            pixels,
663            has_alpha: self.alpha_is_used,
664        })
665    }
666
667    // -----------------------------------------------------------------------
668    // Transform reading
669    // -----------------------------------------------------------------------
670
671    fn read_transforms(&mut self, br: &mut Vp8lBitReader<'_>) -> CodecResult<(u32, u32)> {
672        let mut width = self.width;
673        let height = self.height;
674
675        while br.read_bit()? {
676            let transform_type = br.read_bits(2)?;
677            match transform_type {
678                0 => {
679                    // PREDICTOR_TRANSFORM
680                    let size_bits = br.read_bits(3)? as u8;
681                    let block_size = 1u32 << (size_bits + 2);
682                    let tw = div_round_up(width, block_size);
683                    let th = div_round_up(height, block_size);
684                    let data = self.decode_image_data(br, tw, th)?;
685                    self.transforms.push(Transform::Predictor {
686                        size_bits: size_bits + 2,
687                        data,
688                    });
689                }
690                1 => {
691                    // COLOR_TRANSFORM
692                    let size_bits = br.read_bits(3)? as u8;
693                    let block_size = 1u32 << (size_bits + 2);
694                    let tw = div_round_up(width, block_size);
695                    let th = div_round_up(height, block_size);
696                    let pixels = self.decode_image_data(br, tw, th)?;
697                    let data: Vec<ColorTransformElement> = pixels
698                        .iter()
699                        .map(|&p| ColorTransformElement {
700                            green_to_red: ((p >> 8) & 0xFF) as i8,
701                            green_to_blue: ((p >> 16) & 0xFF) as i8,
702                            red_to_blue: (p & 0xFF) as i8,
703                        })
704                        .collect();
705                    self.transforms.push(Transform::ColorTransform {
706                        size_bits: size_bits + 2,
707                        data,
708                    });
709                }
710                2 => {
711                    // SUBTRACT_GREEN_TRANSFORM
712                    self.transforms.push(Transform::SubtractGreen);
713                }
714                3 => {
715                    // COLOR_INDEXING_TRANSFORM
716                    let num_colors = br.read_bits(8)? + 1;
717                    let palette = self.decode_image_data(br, num_colors, 1)?;
718                    let bits_per_pixel = if num_colors <= 2 {
719                        1
720                    } else if num_colors <= 4 {
721                        2
722                    } else if num_colors <= 16 {
723                        4
724                    } else {
725                        8
726                    };
727                    if bits_per_pixel < 8 {
728                        width = div_round_up(width * u32::from(bits_per_pixel), 8);
729                    }
730                    self.transforms.push(Transform::ColorIndexing {
731                        palette,
732                        bits_per_pixel,
733                    });
734                }
735                _ => {
736                    return Err(CodecError::InvalidBitstream(
737                        "Invalid transform type".into(),
738                    ));
739                }
740            }
741        }
742        Ok((width, height))
743    }
744
745    // -----------------------------------------------------------------------
746    // Image data decoding
747    // -----------------------------------------------------------------------
748
749    fn decode_image_data(
750        &self,
751        br: &mut Vp8lBitReader<'_>,
752        width: u32,
753        height: u32,
754    ) -> CodecResult<Vec<u32>> {
755        // Read color cache parameters.
756        let color_cache_bits = if br.read_bit()? {
757            let bits = br.read_bits(4)?;
758            if bits > MAX_COLOR_CACHE_BITS {
759                return Err(CodecError::InvalidBitstream(format!(
760                    "Color cache bits too large: {bits}"
761                )));
762            }
763            Some(bits)
764        } else {
765            None
766        };
767
768        let num_color_cache_codes = color_cache_bits.map(|b| 1u16 << b).unwrap_or(0);
769
770        // Read meta-Huffman image (entropy image).
771        let huffman_groups = self.read_huffman_codes(br, width, height, num_color_cache_codes)?;
772
773        // Decode pixels.
774        let total_pixels = (width as usize)
775            .checked_mul(height as usize)
776            .ok_or_else(|| CodecError::InvalidBitstream("Image too large".into()))?;
777
778        let mut pixels = vec![0u32; total_pixels];
779        let mut color_cache = color_cache_bits.map(ColorCache::new);
780
781        let mut idx = 0usize;
782        while idx < total_pixels {
783            // For now: single Huffman group (meta-Huffman support below).
784            let group_idx = if huffman_groups.len() == 1 {
785                0
786            } else {
787                // Meta-Huffman: determine group from position.
788                // (In a full implementation, the entropy image would be consulted here.)
789                0
790            };
791            let group = huffman_groups.get(group_idx).ok_or_else(|| {
792                CodecError::InvalidBitstream("Invalid Huffman group index".into())
793            })?;
794
795            let green_sym = group.green.read_symbol(br)?;
796
797            if green_sym < NUM_LITERAL_CODES {
798                // Literal pixel.
799                let red = group.red.read_symbol(br)? as u32;
800                let blue = group.blue.read_symbol(br)? as u32;
801                let alpha = group.alpha.read_symbol(br)? as u32;
802
803                let argb = (alpha << 24) | (red << 16) | (u32::from(green_sym) << 8) | blue;
804                pixels[idx] = argb;
805                if let Some(ref mut cache) = color_cache {
806                    cache.insert(argb);
807                }
808                idx += 1;
809            } else if green_sym < NUM_LITERAL_CODES + NUM_LENGTH_CODES {
810                // LZ77 backward reference.
811                let length_prefix = green_sym - NUM_LITERAL_CODES;
812                let length = prefix_code_to_value(length_prefix, br)?;
813
814                let dist_sym = group.distance.read_symbol(br)?;
815                let dist_raw = prefix_code_to_value(dist_sym, br)?;
816                let dist = distance_map_to_pixel_dist(dist_raw as usize, width as usize);
817
818                if dist == 0 || dist > idx {
819                    return Err(CodecError::InvalidBitstream(format!(
820                        "Invalid backward reference distance: {dist}, position: {idx}"
821                    )));
822                }
823
824                let length = length as usize;
825                for i in 0..length {
826                    if idx + i >= total_pixels {
827                        break;
828                    }
829                    let src = idx + i - dist;
830                    pixels[idx + i] = pixels[src];
831                    if let Some(ref mut cache) = color_cache {
832                        cache.insert(pixels[idx + i]);
833                    }
834                }
835                idx += length;
836            } else {
837                // Color cache lookup.
838                let cache_idx = green_sym - NUM_LITERAL_CODES - NUM_LENGTH_CODES;
839                let cache = color_cache.as_ref().ok_or_else(|| {
840                    CodecError::InvalidBitstream("Color cache code without color cache".into())
841                })?;
842                let argb = cache.lookup(u32::from(cache_idx));
843                pixels[idx] = argb;
844                if let Some(ref mut cache) = color_cache {
845                    cache.insert(argb);
846                }
847                idx += 1;
848            }
849        }
850
851        Ok(pixels)
852    }
853
854    // -----------------------------------------------------------------------
855    // Huffman code reading
856    // -----------------------------------------------------------------------
857
858    fn read_huffman_codes(
859        &self,
860        br: &mut Vp8lBitReader<'_>,
861        _width: u32,
862        _height: u32,
863        num_color_cache_codes: u16,
864    ) -> CodecResult<Vec<HuffmanGroup>> {
865        // Check for meta-Huffman image.
866        let use_meta = br.read_bit()?;
867        let num_groups = if use_meta {
868            let _prefix_bits = br.read_bits(3)? + 2;
869            // For a full meta-Huffman implementation, we would read
870            // the entropy image here. For now, treat as single group.
871            // The entropy image would tell us the number of groups.
872            1usize
873        } else {
874            1usize
875        };
876
877        if num_groups > MAX_HUFFMAN_GROUPS {
878            return Err(CodecError::InvalidBitstream(
879                "Too many Huffman groups".into(),
880            ));
881        }
882
883        let green_alphabet = NUM_LITERAL_CODES + NUM_LENGTH_CODES + num_color_cache_codes;
884        let red_alphabet = NUM_LITERAL_CODES;
885        let blue_alphabet = NUM_LITERAL_CODES;
886        let alpha_alphabet = NUM_LITERAL_CODES;
887        let dist_alphabet = NUM_DISTANCE_CODES;
888
889        let mut groups = Vec::with_capacity(num_groups);
890        for _ in 0..num_groups {
891            let green = read_huffman_tree(br, green_alphabet)?;
892            let red = read_huffman_tree(br, red_alphabet)?;
893            let blue = read_huffman_tree(br, blue_alphabet)?;
894            let alpha = read_huffman_tree(br, alpha_alphabet)?;
895            let distance = read_huffman_tree(br, dist_alphabet)?;
896
897            groups.push(HuffmanGroup {
898                green,
899                red,
900                blue,
901                alpha,
902                distance,
903            });
904        }
905
906        Ok(groups)
907    }
908
909    // -----------------------------------------------------------------------
910    // Inverse transforms
911    // -----------------------------------------------------------------------
912
913    fn apply_transforms(
914        &self,
915        mut pixels: Vec<u32>,
916        decoded_width: u32,
917        decoded_height: u32,
918    ) -> CodecResult<Vec<u32>> {
919        // Apply in reverse order.
920        for transform in self.transforms.iter().rev() {
921            match transform {
922                Transform::Predictor { size_bits, data } => {
923                    pixels = self.inverse_predictor(
924                        &pixels,
925                        decoded_width,
926                        decoded_height,
927                        *size_bits,
928                        data,
929                    )?;
930                }
931                Transform::ColorTransform { size_bits, data } => {
932                    pixels = self.inverse_color_transform(
933                        &pixels,
934                        decoded_width,
935                        decoded_height,
936                        *size_bits,
937                        data,
938                    );
939                }
940                Transform::SubtractGreen => {
941                    self.inverse_subtract_green(&mut pixels);
942                }
943                Transform::ColorIndexing {
944                    palette,
945                    bits_per_pixel,
946                } => {
947                    pixels = self.inverse_color_indexing(
948                        &pixels,
949                        decoded_width,
950                        decoded_height,
951                        palette,
952                        *bits_per_pixel,
953                    )?;
954                }
955            }
956        }
957        Ok(pixels)
958    }
959
960    /// Inverse predictor transform: add predicted values to residuals.
961    fn inverse_predictor(
962        &self,
963        pixels: &[u32],
964        width: u32,
965        height: u32,
966        size_bits: u8,
967        predictor_data: &[u32],
968    ) -> CodecResult<Vec<u32>> {
969        let w = width as usize;
970        let h = height as usize;
971        let block_size = 1usize << size_bits;
972        let pred_w = div_round_up(width, block_size as u32) as usize;
973
974        let mut out = pixels.to_vec();
975
976        // Top-left pixel: add to 0xFF000000.
977        if !out.is_empty() {
978            out[0] = add_pixels(out[0], 0xFF00_0000);
979        }
980
981        // Top row: predictor mode 1 (left).
982        for x in 1..w.min(out.len()) {
983            out[x] = add_pixels(out[x], out[x - 1]);
984        }
985
986        // Remaining rows.
987        for y in 1..h {
988            let row_start = y * w;
989            if row_start >= out.len() {
990                break;
991            }
992            // Left column: predictor mode 2 (top).
993            out[row_start] = add_pixels(out[row_start], out[row_start - w]);
994
995            for x in 1..w {
996                let idx = row_start + x;
997                if idx >= out.len() {
998                    break;
999                }
1000                let bx = x / block_size;
1001                let by = (y - 1) / block_size;
1002                let pred_idx = by * pred_w + bx;
1003                let mode = if pred_idx < predictor_data.len() {
1004                    ((predictor_data[pred_idx] >> 8) & 0xFF) as u8
1005                } else {
1006                    0
1007                };
1008
1009                let left = out[idx - 1];
1010                let top = out[idx - w];
1011                let top_left = out[idx - w - 1];
1012                let top_right = if x + 1 < w {
1013                    out[idx - w + 1]
1014                } else {
1015                    out[idx - w]
1016                };
1017
1018                let predicted = predict(mode, left, top, top_left, top_right);
1019                out[idx] = add_pixels(out[idx], predicted);
1020            }
1021        }
1022
1023        Ok(out)
1024    }
1025
1026    /// Inverse color transform.
1027    fn inverse_color_transform(
1028        &self,
1029        pixels: &[u32],
1030        width: u32,
1031        height: u32,
1032        size_bits: u8,
1033        transform_data: &[ColorTransformElement],
1034    ) -> Vec<u32> {
1035        let w = width as usize;
1036        let h = height as usize;
1037        let block_size = 1usize << size_bits;
1038        let tw = div_round_up(width, block_size as u32) as usize;
1039
1040        let mut out = pixels.to_vec();
1041
1042        for y in 0..h {
1043            for x in 0..w {
1044                let idx = y * w + x;
1045                if idx >= out.len() {
1046                    break;
1047                }
1048                let bx = x / block_size;
1049                let by = y / block_size;
1050                let ti = by * tw + bx;
1051                let ct = if ti < transform_data.len() {
1052                    transform_data[ti]
1053                } else {
1054                    ColorTransformElement::default()
1055                };
1056
1057                let argb = out[idx];
1058                let green = ((argb >> 8) & 0xFF) as i32;
1059                let red = ((argb >> 16) & 0xFF) as i32;
1060                let blue = (argb & 0xFF) as i32;
1061                let alpha = (argb >> 24) & 0xFF;
1062
1063                let new_red = (red + color_transform_delta(ct.green_to_red as i32, green)) & 0xFF;
1064                let new_blue = (blue
1065                    + color_transform_delta(ct.green_to_blue as i32, green)
1066                    + color_transform_delta(ct.red_to_blue as i32, new_red))
1067                    & 0xFF;
1068
1069                out[idx] = (alpha << 24)
1070                    | ((new_red as u32) << 16)
1071                    | (((green as u32) & 0xFF) << 8)
1072                    | (new_blue as u32);
1073            }
1074        }
1075
1076        out
1077    }
1078
1079    /// Inverse subtract-green transform.
1080    fn inverse_subtract_green(&self, pixels: &mut [u32]) {
1081        for pixel in pixels.iter_mut() {
1082            let green = (*pixel >> 8) & 0xFF;
1083            let red = ((*pixel >> 16) & 0xFF).wrapping_add(green) & 0xFF;
1084            let blue = (*pixel & 0xFF).wrapping_add(green) & 0xFF;
1085            *pixel = (*pixel & 0xFF00_FF00) | (red << 16) | blue;
1086        }
1087    }
1088
1089    /// Inverse color indexing transform.
1090    fn inverse_color_indexing(
1091        &self,
1092        pixels: &[u32],
1093        _packed_width: u32,
1094        height: u32,
1095        palette: &[u32],
1096        bits_per_pixel: u8,
1097    ) -> CodecResult<Vec<u32>> {
1098        let out_width = self.width as usize;
1099        let out_height = height as usize;
1100        let total = out_width * out_height;
1101        let mut out = Vec::with_capacity(total);
1102
1103        let pixels_per_byte = 8 / bits_per_pixel as usize;
1104        let mask = (1u32 << bits_per_pixel) - 1;
1105
1106        for y in 0..out_height {
1107            for x in 0..out_width {
1108                let packed_x = x / pixels_per_byte;
1109                let sub_idx = x % pixels_per_byte;
1110                let src_idx = y * (_packed_width as usize) + packed_x;
1111                let packed_val = if src_idx < pixels.len() {
1112                    // Green channel holds the packed index.
1113                    (pixels[src_idx] >> 8) & 0xFF
1114                } else {
1115                    0
1116                };
1117
1118                let index = (packed_val >> (sub_idx as u32 * u32::from(bits_per_pixel))) & mask;
1119                let color = if (index as usize) < palette.len() {
1120                    palette[index as usize]
1121                } else {
1122                    0xFF00_0000
1123                };
1124                out.push(color);
1125            }
1126        }
1127
1128        Ok(out)
1129    }
1130}
1131
1132impl Default for Vp8lDecoder {
1133    fn default() -> Self {
1134        Self::new()
1135    }
1136}
1137
1138// Huffman tree reading
1139
1140/// Read a Huffman tree from the bitstream.
1141fn read_huffman_tree(br: &mut Vp8lBitReader<'_>, alphabet_size: u16) -> CodecResult<HuffmanTree> {
1142    let simple = br.read_bit()?;
1143    if simple {
1144        read_simple_huffman(br, alphabet_size)
1145    } else {
1146        read_normal_huffman(br, alphabet_size)
1147    }
1148}
1149
1150/// Read a simple (1 or 2 symbol) Huffman code.
1151fn read_simple_huffman(br: &mut Vp8lBitReader<'_>, alphabet_size: u16) -> CodecResult<HuffmanTree> {
1152    let num_symbols = br.read_bits(1)? + 1;
1153    let is_first_8bit = br.read_bit()?;
1154
1155    let symbol0 = if is_first_8bit {
1156        br.read_bits(8)? as u16
1157    } else {
1158        br.read_bits(1)? as u16
1159    };
1160
1161    if symbol0 >= alphabet_size {
1162        return Err(CodecError::InvalidBitstream(format!(
1163            "Simple Huffman symbol {symbol0} >= alphabet size {alphabet_size}"
1164        )));
1165    }
1166
1167    if num_symbols == 1 {
1168        let mut code_lengths = vec![0u8; alphabet_size as usize];
1169        code_lengths[symbol0 as usize] = 1;
1170        // Single-symbol tree: always returns this symbol.
1171        let lut = vec![
1172            HuffmanCode {
1173                bits: 0,
1174                value: symbol0,
1175            };
1176            1
1177        ];
1178        return Ok(HuffmanTree {
1179            lut,
1180            lut_bits: 0,
1181            second_level: Vec::new(),
1182            lut2: Vec::new(),
1183        });
1184    }
1185
1186    // Two symbols, 1-bit code.
1187    let symbol1 = br.read_bits(8)? as u16;
1188    if symbol1 >= alphabet_size {
1189        return Err(CodecError::InvalidBitstream(format!(
1190            "Simple Huffman symbol {symbol1} >= alphabet size {alphabet_size}"
1191        )));
1192    }
1193
1194    let mut code_lengths = vec![0u8; alphabet_size as usize];
1195    code_lengths[symbol0 as usize] = 1;
1196    code_lengths[symbol1 as usize] = 1;
1197    HuffmanTree::build(&code_lengths, alphabet_size)
1198}
1199
1200/// Read a normal (complex) Huffman code using the code-length-code method.
1201fn read_normal_huffman(br: &mut Vp8lBitReader<'_>, alphabet_size: u16) -> CodecResult<HuffmanTree> {
1202    // Read the number of code length codes.
1203    let num_code_length_codes = br.read_bits(4)? as usize + 4;
1204    if num_code_length_codes > NUM_CODE_LENGTH_CODES {
1205        return Err(CodecError::InvalidBitstream(format!(
1206            "Too many code length codes: {num_code_length_codes}"
1207        )));
1208    }
1209
1210    // Read code length code lengths (3 bits each).
1211    let mut cl_code_lengths = [0u8; NUM_CODE_LENGTH_CODES];
1212    for i in 0..num_code_length_codes {
1213        cl_code_lengths[CODE_LENGTH_CODE_ORDER[i] as usize] = br.read_bits(3)? as u8;
1214    }
1215
1216    // Build the code-length Huffman tree.
1217    let cl_tree = HuffmanTree::build(&cl_code_lengths, NUM_CODE_LENGTH_CODES as u16)?;
1218
1219    // Decode actual code lengths.
1220    let mut code_lengths = vec![0u8; alphabet_size as usize];
1221    let mut i = 0usize;
1222    let mut prev_code_length = 8u8;
1223
1224    while i < alphabet_size as usize {
1225        let sym = cl_tree.read_symbol(br)?;
1226        match sym {
1227            0..=15 => {
1228                code_lengths[i] = sym as u8;
1229                if sym != 0 {
1230                    prev_code_length = sym as u8;
1231                }
1232                i += 1;
1233            }
1234            16 => {
1235                // Repeat previous code length 3-6 times.
1236                let repeat = br.read_bits(2)? as usize + 3;
1237                for _ in 0..repeat {
1238                    if i >= alphabet_size as usize {
1239                        break;
1240                    }
1241                    code_lengths[i] = prev_code_length;
1242                    i += 1;
1243                }
1244            }
1245            17 => {
1246                // Repeat zero 3-10 times.
1247                let repeat = br.read_bits(3)? as usize + 3;
1248                i += repeat;
1249            }
1250            18 => {
1251                // Repeat zero 11-138 times.
1252                let repeat = br.read_bits(7)? as usize + 11;
1253                i += repeat;
1254            }
1255            _ => {
1256                return Err(CodecError::InvalidBitstream(format!(
1257                    "Invalid code length symbol: {sym}"
1258                )));
1259            }
1260        }
1261    }
1262
1263    HuffmanTree::build(&code_lengths, alphabet_size)
1264}
1265
1266// Prefix / LZ77 helpers
1267
1268/// Convert a prefix code + extra bits to a value (used for length and distance).
1269fn prefix_code_to_value(prefix_code: u16, br: &mut Vp8lBitReader<'_>) -> CodecResult<u32> {
1270    if prefix_code < 4 {
1271        return Ok(u32::from(prefix_code) + 1);
1272    }
1273    let extra_bits = (u32::from(prefix_code) - 2) >> 1;
1274    let offset = (2 + (u32::from(prefix_code) & 1)) << extra_bits;
1275    let extra = br.read_bits(extra_bits)?;
1276    Ok(offset + extra + 1)
1277}
1278
1279/// Map a VP8L distance code to a pixel distance using the 2D distance table.
1280fn distance_map_to_pixel_dist(dist_code: usize, xsize: usize) -> usize {
1281    if dist_code == 0 {
1282        return 0;
1283    }
1284    if dist_code <= 120 {
1285        let (dx, dy) = DISTANCE_MAP[dist_code - 1];
1286        let dist = i64::from(dy) * xsize as i64 + i64::from(dx);
1287        if dist < 1 {
1288            return 1;
1289        }
1290        dist as usize
1291    } else {
1292        dist_code - 120
1293    }
1294}
1295
1296// Pixel arithmetic helpers — extracted to `vp8l_pixel` module.
1297use super::vp8l_pixel::{
1298    add_pixels, average2, channels_to_pixel, clamp_add_subtract_full, clamp_add_subtract_half,
1299    color_transform_delta, div_round_up, pixel_channels, predict, select,
1300};
1301
1302// Tests
1303
1304#[cfg(test)]
1305mod tests {
1306    use super::*;
1307
1308    // -- Header tests -------------------------------------------------------
1309
1310    #[test]
1311    fn test_parse_header_basic() {
1312        // Construct a valid VP8L header for a 4x3 image, no alpha, version 0.
1313        // width = 4 => width-1 = 3 (14 bits: 0x0003)
1314        // height = 3 => height-1 = 2 (14 bits: 0x0002)
1315        // alpha = 0 (1 bit)
1316        // version = 0 (3 bits)
1317        // Packed: 3 | (2 << 14) | (0 << 28) | (0 << 29)
1318        let val: u32 = 3 | (2 << 14);
1319        let mut data = vec![VP8L_SIGNATURE];
1320        data.extend_from_slice(&val.to_le_bytes());
1321
1322        let header = Vp8lHeader::parse(&data).expect("should parse");
1323        assert_eq!(header.width, 4);
1324        assert_eq!(header.height, 3);
1325        assert!(!header.alpha_is_used);
1326        assert_eq!(header.version, 0);
1327    }
1328
1329    #[test]
1330    fn test_parse_header_with_alpha() {
1331        // 10x5, alpha used.
1332        let val: u32 = 9 | (4 << 14) | (1 << 28);
1333        let mut data = vec![VP8L_SIGNATURE];
1334        data.extend_from_slice(&val.to_le_bytes());
1335
1336        let header = Vp8lHeader::parse(&data).expect("should parse");
1337        assert_eq!(header.width, 10);
1338        assert_eq!(header.height, 5);
1339        assert!(header.alpha_is_used);
1340        assert_eq!(header.version, 0);
1341    }
1342
1343    #[test]
1344    fn test_parse_header_bad_signature() {
1345        let data = [0x00, 0x00, 0x00, 0x00, 0x00];
1346        assert!(Vp8lHeader::parse(&data).is_err());
1347    }
1348
1349    #[test]
1350    fn test_parse_header_bad_version() {
1351        let val: u32 = 3 | (2 << 14) | (1 << 29); // version = 1
1352        let mut data = vec![VP8L_SIGNATURE];
1353        data.extend_from_slice(&val.to_le_bytes());
1354        assert!(Vp8lHeader::parse(&data).is_err());
1355    }
1356
1357    #[test]
1358    fn test_parse_header_too_short() {
1359        let data = [VP8L_SIGNATURE, 0x00];
1360        assert!(Vp8lHeader::parse(&data).is_err());
1361    }
1362
1363    // -- Bit reader tests ---------------------------------------------------
1364
1365    #[test]
1366    fn test_bitreader_read_bits() {
1367        // 0xA5 = 1010_0101 in binary
1368        // LSB-first reading: bit0=1, bit1=0, bit2=1, bit3=0, bit4=0, bit5=1, ...
1369        let data = [0xA5, 0xFF];
1370        let mut br = Vp8lBitReader::new(&data);
1371        // Read 4 bits LSB-first from 0xA5 => bottom nibble = 0x5
1372        let val = br.read_bits(4).expect("should read");
1373        assert_eq!(val, 0x5);
1374        // Next 4 bits => top nibble = 0xA
1375        let val = br.read_bits(4).expect("should read");
1376        assert_eq!(val, 0xA);
1377    }
1378
1379    #[test]
1380    fn test_bitreader_read_bit() {
1381        let data = [0x01];
1382        let mut br = Vp8lBitReader::new(&data);
1383        assert!(br.read_bit().expect("should read")); // LSB is 1
1384        assert!(!br.read_bit().expect("should read")); // next bit is 0
1385    }
1386
1387    #[test]
1388    fn test_bitreader_read_zero_bits() {
1389        let data = [0xFF];
1390        let mut br = Vp8lBitReader::new(&data);
1391        assert_eq!(br.read_bits(0).expect("should read"), 0);
1392    }
1393
1394    #[test]
1395    fn test_bitreader_peek_and_advance() {
1396        let data = [0xAB, 0xCD];
1397        let mut br = Vp8lBitReader::new(&data);
1398        let peeked = br.peek_bits(8).expect("should peek");
1399        assert_eq!(peeked, 0xAB);
1400        br.advance(4);
1401        let next = br.read_bits(4).expect("should read");
1402        assert_eq!(next, 0x0A); // upper nibble of 0xAB
1403    }
1404
1405    // -- Reverse bits -------------------------------------------------------
1406
1407    #[test]
1408    fn test_reverse_bits() {
1409        assert_eq!(reverse_bits(0b110, 3), 0b011);
1410        assert_eq!(reverse_bits(0b1010, 4), 0b0101);
1411        assert_eq!(reverse_bits(0b1, 1), 0b1);
1412        assert_eq!(reverse_bits(0b0, 1), 0b0);
1413    }
1414
1415    // -- Pixel helpers ------------------------------------------------------
1416
1417    #[test]
1418    fn test_add_pixels() {
1419        let a = 0x01020304u32;
1420        let b = 0x05060708u32;
1421        let result = add_pixels(a, b);
1422        assert_eq!((result >> 24) & 0xFF, 0x06);
1423        assert_eq!((result >> 16) & 0xFF, 0x08);
1424        assert_eq!((result >> 8) & 0xFF, 0x0A);
1425        assert_eq!(result & 0xFF, 0x0C);
1426    }
1427
1428    #[test]
1429    fn test_add_pixels_wrapping() {
1430        let a = 0xFF800180u32;
1431        let b = 0x01810281u32;
1432        let result = add_pixels(a, b);
1433        assert_eq!((result >> 24) & 0xFF, 0x00); // 0xFF + 0x01 = 0x100 & 0xFF = 0x00
1434        assert_eq!((result >> 16) & 0xFF, 0x01); // 0x80 + 0x81 = 0x101 & 0xFF = 0x01
1435        assert_eq!((result >> 8) & 0xFF, 0x03); // 0x01 + 0x02 = 0x03
1436        assert_eq!(result & 0xFF, 0x01); // 0x80 + 0x81 = 0x101 & 0xFF = 0x01
1437    }
1438
1439    #[test]
1440    fn test_average2() {
1441        let a = 0xFF000000u32;
1442        let b = 0xFF000000u32;
1443        assert_eq!(average2(a, b), 0xFF000000);
1444
1445        let a = 0xFF640000u32; // R=100
1446        let b = 0xFFC80000u32; // R=200
1447        let result = average2(a, b);
1448        assert_eq!((result >> 16) & 0xFF, 150); // average of 100 and 200
1449    }
1450
1451    #[test]
1452    fn test_select_predictor() {
1453        // predict_l = sum|T[i] - TL[i]|, predict_t = sum|L[i] - TL[i]|
1454        // When predict_l < predict_t, return left.
1455        let left = 0xFF640000u32; // R=100
1456        let top = 0xFF0A0000u32; // R=10
1457        let top_left = 0xFF0A0000u32; // R=10
1458                                      // predict_l = |10 - 10| = 0, predict_t = |100 - 10| = 90
1459                                      // predict_l < predict_t => return left
1460        let result = select(left, top, top_left);
1461        assert_eq!(result, left);
1462    }
1463
1464    #[test]
1465    fn test_clamp_add_subtract_full() {
1466        let left = channels_to_pixel([255, 100, 50, 30]);
1467        let top = channels_to_pixel([255, 80, 60, 20]);
1468        let top_left = channels_to_pixel([255, 90, 55, 25]);
1469        // L + T - TL per channel: (100+80-90)=90, (50+60-55)=55, (30+20-25)=25
1470        let result = clamp_add_subtract_full(left, top, top_left);
1471        let ch = pixel_channels(result);
1472        assert_eq!(ch[0], 255);
1473        assert_eq!(ch[1], 90);
1474        assert_eq!(ch[2], 55);
1475        assert_eq!(ch[3], 25);
1476    }
1477
1478    #[test]
1479    fn test_clamp_add_subtract_full_clamping() {
1480        let left = channels_to_pixel([255, 250, 10, 5]);
1481        let top = channels_to_pixel([255, 240, 5, 3]);
1482        let top_left = channels_to_pixel([255, 100, 200, 200]);
1483        // L + T - TL: (250+240-100)=390 clamped to 255, (10+5-200)=-185 clamped to 0
1484        let result = clamp_add_subtract_full(left, top, top_left);
1485        let ch = pixel_channels(result);
1486        assert_eq!(ch[1], 255);
1487        assert_eq!(ch[2], 0);
1488        assert_eq!(ch[3], 0);
1489    }
1490
1491    // -- Distance mapping ---------------------------------------------------
1492
1493    #[test]
1494    fn test_distance_map_code_1() {
1495        // Code 1 => (0, 1) => dist = 1*width + 0 = width
1496        let dist = distance_map_to_pixel_dist(1, 10);
1497        assert_eq!(dist, 10);
1498    }
1499
1500    #[test]
1501    fn test_distance_map_code_2() {
1502        // Code 2 => (1, 0) => dist = 0*width + 1 = 1
1503        let dist = distance_map_to_pixel_dist(2, 10);
1504        assert_eq!(dist, 1);
1505    }
1506
1507    #[test]
1508    fn test_distance_map_negative_dx() {
1509        // Code 4 => (-1, 1) => dist = 1*width + (-1) = width - 1
1510        let dist = distance_map_to_pixel_dist(4, 10);
1511        assert_eq!(dist, 9);
1512    }
1513
1514    #[test]
1515    fn test_distance_map_over_120() {
1516        // Code > 120 => dist_code - 120
1517        let dist = distance_map_to_pixel_dist(130, 10);
1518        assert_eq!(dist, 10);
1519    }
1520
1521    #[test]
1522    fn test_distance_map_clamp_to_1() {
1523        // Code 2 => (1, 0) => dist = 1 with any width
1524        // Code 1 => (0, 1) => dist = width; for width=1 => dist=1
1525        let dist = distance_map_to_pixel_dist(1, 1);
1526        assert_eq!(dist, 1);
1527    }
1528
1529    // -- Prefix code --------------------------------------------------------
1530
1531    #[test]
1532    fn test_prefix_code_small() {
1533        // Codes 0-3 map directly to values 1-4.
1534        let data = [0xFF; 4];
1535        let mut br = Vp8lBitReader::new(&data);
1536        assert_eq!(prefix_code_to_value(0, &mut br).expect("ok"), 1);
1537        assert_eq!(prefix_code_to_value(1, &mut br).expect("ok"), 2);
1538        assert_eq!(prefix_code_to_value(2, &mut br).expect("ok"), 3);
1539        assert_eq!(prefix_code_to_value(3, &mut br).expect("ok"), 4);
1540    }
1541
1542    #[test]
1543    fn test_prefix_code_with_extra_bits() {
1544        // Code 4: extra_bits = (4-2)>>1 = 1, offset = (2+(4&1))<<1 = 4
1545        // With extra bit = 0: value = 4 + 0 + 1 = 5
1546        let data = [0x00; 4];
1547        let mut br = Vp8lBitReader::new(&data);
1548        assert_eq!(prefix_code_to_value(4, &mut br).expect("ok"), 5);
1549    }
1550
1551    // -- Huffman tree building ----------------------------------------------
1552
1553    #[test]
1554    fn test_huffman_single_symbol() {
1555        // Single-symbol tree.
1556        let code_lengths = [0u8, 1, 0, 0];
1557        let tree = HuffmanTree::build(&code_lengths, 4).expect("should build");
1558        let data = [0x00; 4];
1559        let mut br = Vp8lBitReader::new(&data);
1560        let sym = tree.read_symbol(&mut br).expect("should decode");
1561        assert_eq!(sym, 1);
1562    }
1563
1564    #[test]
1565    fn test_huffman_two_symbols() {
1566        // Two-symbol tree: symbol 0 = code 0 (1 bit), symbol 1 = code 1 (1 bit).
1567        let code_lengths = [1u8, 1];
1568        let tree = HuffmanTree::build(&code_lengths, 2).expect("should build");
1569
1570        // Bit 0 => symbol 0
1571        let data = [0x00];
1572        let mut br = Vp8lBitReader::new(&data);
1573        assert_eq!(tree.read_symbol(&mut br).expect("ok"), 0);
1574
1575        // Bit 1 => symbol 1
1576        let data = [0x01];
1577        let mut br = Vp8lBitReader::new(&data);
1578        assert_eq!(tree.read_symbol(&mut br).expect("ok"), 1);
1579    }
1580
1581    #[test]
1582    fn test_huffman_three_symbols() {
1583        // Three symbols: 0 => len 1, 1 => len 2, 2 => len 2.
1584        // Canonical codes: 0 => "0", 1 => "10", 2 => "11"
1585        let code_lengths = [1u8, 2, 2];
1586        let tree = HuffmanTree::build(&code_lengths, 3).expect("should build");
1587
1588        // "0" (bit 0) => symbol 0
1589        let data = [0b0000_0000];
1590        let mut br = Vp8lBitReader::new(&data);
1591        assert_eq!(tree.read_symbol(&mut br).expect("ok"), 0);
1592
1593        // Canonical code for symbol 1 = "10", reversed LSB-first = "01" = 1.
1594        // Bottom 2 bits of data must be 0b01.
1595        let data = [0b0000_0001];
1596        let mut br = Vp8lBitReader::new(&data);
1597        assert_eq!(tree.read_symbol(&mut br).expect("ok"), 1);
1598
1599        // Canonical code for symbol 2 = "11", reversed LSB-first = "11" = 3.
1600        // Bottom 2 bits of data must be 0b11.
1601        let data = [0b0000_0011];
1602        let mut br = Vp8lBitReader::new(&data);
1603        assert_eq!(tree.read_symbol(&mut br).expect("ok"), 2);
1604    }
1605
1606    // -- Inverse subtract green ---------------------------------------------
1607
1608    #[test]
1609    fn test_inverse_subtract_green() {
1610        let decoder = Vp8lDecoder::new();
1611        let mut pixels = vec![0x00_20_40_60u32]; // A=0x00, R=0x20, G=0x40, B=0x60
1612        decoder.inverse_subtract_green(&mut pixels);
1613        // R += G: (0x20 + 0x40) & 0xFF = 0x60
1614        // B += G: (0x60 + 0x40) & 0xFF = 0xA0
1615        assert_eq!((pixels[0] >> 16) & 0xFF, 0x60);
1616        assert_eq!(pixels[0] & 0xFF, 0xA0);
1617        // G unchanged
1618        assert_eq!((pixels[0] >> 8) & 0xFF, 0x40);
1619    }
1620
1621    // -- Color transform delta ----------------------------------------------
1622
1623    #[test]
1624    fn test_color_transform_delta() {
1625        // Simple: 4 * 8 >> 5 = 1
1626        assert_eq!(color_transform_delta(4, 8), 1);
1627        // Negative multiplier: -4 * 8 >> 5 = -1
1628        assert_eq!(color_transform_delta(-4i32 as i32, 8), -1);
1629    }
1630
1631    // -- predict function ---------------------------------------------------
1632
1633    #[test]
1634    fn test_predict_modes() {
1635        let left = 0xFF112233u32;
1636        let top = 0xFF445566u32;
1637        let top_left = 0xFF778899u32;
1638        let top_right = 0xFFAABBCCu32;
1639
1640        assert_eq!(predict(0, left, top, top_left, top_right), 0xFF000000);
1641        assert_eq!(predict(1, left, top, top_left, top_right), left);
1642        assert_eq!(predict(2, left, top, top_left, top_right), top);
1643        assert_eq!(predict(3, left, top, top_left, top_right), top_right);
1644        assert_eq!(predict(4, left, top, top_left, top_right), top_left);
1645    }
1646
1647    #[test]
1648    fn test_predict_average_modes() {
1649        let left = channels_to_pixel([255, 100, 50, 30]);
1650        let top = channels_to_pixel([255, 200, 100, 60]);
1651
1652        // Mode 7: Average2(L, T)
1653        let result = predict(7, left, top, left, top);
1654        let ch = pixel_channels(result);
1655        assert_eq!(ch[1], 150); // avg(100, 200)
1656        assert_eq!(ch[2], 75); // avg(50, 100)
1657        assert_eq!(ch[3], 45); // avg(30, 60)
1658    }
1659
1660    // -- div_round_up -------------------------------------------------------
1661
1662    #[test]
1663    fn test_div_round_up() {
1664        assert_eq!(div_round_up(10, 3), 4);
1665        assert_eq!(div_round_up(9, 3), 3);
1666        assert_eq!(div_round_up(1, 1), 1);
1667        assert_eq!(div_round_up(0, 5), 0);
1668    }
1669
1670    // -- Color cache --------------------------------------------------------
1671
1672    #[test]
1673    fn test_color_cache() {
1674        let mut cache = ColorCache::new(4); // 16 entries
1675        let color = 0xFF112233u32;
1676        cache.insert(color);
1677        // The hash determines the slot; verify that the color is retrievable.
1678        let hash = (0x1E35_A7BDu64.wrapping_mul(u64::from(color)) >> 28) as u32;
1679        assert_eq!(cache.lookup(hash), color);
1680    }
1681
1682    // -- Decoder new --------------------------------------------------------
1683
1684    #[test]
1685    fn test_decoder_new() {
1686        let decoder = Vp8lDecoder::new();
1687        assert_eq!(decoder.width, 0);
1688        assert_eq!(decoder.height, 0);
1689    }
1690
1691    #[test]
1692    fn test_decoder_default() {
1693        let decoder = Vp8lDecoder::default();
1694        assert_eq!(decoder.width, 0);
1695    }
1696
1697    // -- Synthetic VP8L bitstream -------------------------------------------
1698
1699    /// Build a minimal valid VP8L bitstream for a 1x1 solid-color image.
1700    /// This uses a simple Huffman code with a single literal pixel.
1701    fn build_1x1_bitstream(argb: u32) -> Vec<u8> {
1702        let green = ((argb >> 8) & 0xFF) as u8;
1703        let red = ((argb >> 16) & 0xFF) as u8;
1704        let blue = (argb & 0xFF) as u8;
1705        let alpha = ((argb >> 24) & 0xFF) as u8;
1706
1707        // We build the bitstream manually:
1708        // 1. Header: signature(1) + packed(4) = 5 bytes
1709        // 2. No transforms (1 bit = 0)
1710        // 3. No color cache (1 bit = 0)
1711        // 4. No meta-Huffman (1 bit = 0)
1712        // 5. Five simple Huffman codes (1-symbol each)
1713        // 6. The single pixel
1714
1715        let mut bits = BitWriter::new();
1716
1717        // Transform flag: no transforms.
1718        bits.write(0, 1);
1719
1720        // Color cache: no.
1721        bits.write(0, 1);
1722
1723        // Meta-Huffman: no.
1724        bits.write(0, 1);
1725
1726        // Five Huffman trees, each "simple" with 1 symbol.
1727        // Green tree: simple=1, num_symbols-1=0, is_first_8bit=1, symbol=green
1728        write_single_symbol_tree(&mut bits, u16::from(green));
1729        // Red tree
1730        write_single_symbol_tree(&mut bits, u16::from(red));
1731        // Blue tree
1732        write_single_symbol_tree(&mut bits, u16::from(blue));
1733        // Alpha tree
1734        write_single_symbol_tree(&mut bits, u16::from(alpha));
1735        // Distance tree: symbol 0
1736        write_single_symbol_tree(&mut bits, 0);
1737
1738        // The pixel: since each tree has exactly 1 symbol, 0 bits needed per symbol.
1739        // (Single-symbol trees decode without reading any bits.)
1740
1741        let body = bits.finish();
1742
1743        // Build header.
1744        let val: u32 = 0 | (0 << 14); // width-1=0, height-1=0
1745                                      // alpha flag
1746        let val = val | if alpha != 255 { 1 << 28 } else { 0 };
1747        let mut data = vec![VP8L_SIGNATURE];
1748        data.extend_from_slice(&val.to_le_bytes());
1749        data.extend_from_slice(&body);
1750        data
1751    }
1752
1753    /// Write a simple single-symbol Huffman tree into the bit writer.
1754    fn write_single_symbol_tree(bw: &mut BitWriter, symbol: u16) {
1755        // simple = 1
1756        bw.write(1, 1);
1757        // num_symbols - 1 = 0
1758        bw.write(0, 1);
1759        // is_first_8bit = 1 (so we can encode symbol in 8 bits)
1760        bw.write(1, 1);
1761        // symbol (8 bits)
1762        bw.write(u32::from(symbol), 8);
1763    }
1764
1765    /// Simple LSB-first bit writer for test data construction.
1766    struct BitWriter {
1767        bytes: Vec<u8>,
1768        current: u64,
1769        bits_used: u32,
1770    }
1771
1772    impl BitWriter {
1773        fn new() -> Self {
1774            Self {
1775                bytes: Vec::new(),
1776                current: 0,
1777                bits_used: 0,
1778            }
1779        }
1780
1781        fn write(&mut self, val: u32, n: u32) {
1782            self.current |= u64::from(val) << self.bits_used;
1783            self.bits_used += n;
1784            while self.bits_used >= 8 {
1785                self.bytes.push((self.current & 0xFF) as u8);
1786                self.current >>= 8;
1787                self.bits_used -= 8;
1788            }
1789        }
1790
1791        fn finish(mut self) -> Vec<u8> {
1792            if self.bits_used > 0 {
1793                self.bytes.push((self.current & 0xFF) as u8);
1794            }
1795            self.bytes
1796        }
1797    }
1798
1799    #[test]
1800    fn test_decode_1x1_white() {
1801        let data = build_1x1_bitstream(0xFFFF_FFFF);
1802        let mut decoder = Vp8lDecoder::new();
1803        let result = decoder.decode(&data).expect("should decode");
1804        assert_eq!(result.width, 1);
1805        assert_eq!(result.height, 1);
1806        assert_eq!(result.pixels.len(), 1);
1807        assert_eq!(result.pixels[0], 0xFFFF_FFFF);
1808    }
1809
1810    #[test]
1811    fn test_decode_1x1_red() {
1812        let data = build_1x1_bitstream(0xFFFF_0000);
1813        let mut decoder = Vp8lDecoder::new();
1814        let result = decoder.decode(&data).expect("should decode");
1815        assert_eq!(result.pixels[0], 0xFFFF_0000);
1816    }
1817
1818    #[test]
1819    fn test_decode_1x1_with_alpha() {
1820        let data = build_1x1_bitstream(0x80FF_0000);
1821        let mut decoder = Vp8lDecoder::new();
1822        let result = decoder.decode(&data).expect("should decode");
1823        assert_eq!(result.pixels[0], 0x80FF_0000);
1824        assert!(result.has_alpha);
1825    }
1826
1827    #[test]
1828    fn test_decode_1x1_black() {
1829        let data = build_1x1_bitstream(0xFF00_0000);
1830        let mut decoder = Vp8lDecoder::new();
1831        let result = decoder.decode(&data).expect("should decode");
1832        assert_eq!(result.pixels[0], 0xFF00_0000);
1833    }
1834
1835    #[test]
1836    fn test_decode_invalid_data() {
1837        let data = [0x00, 0x01]; // too short, wrong sig
1838        let mut decoder = Vp8lDecoder::new();
1839        assert!(decoder.decode(&data).is_err());
1840    }
1841
1842    /// Build a 2x2 bitstream with 4 literal pixels, no transforms.
1843    fn build_2x2_bitstream(pixels: [u32; 4]) -> Vec<u8> {
1844        // We use two-symbol Huffman codes for channels that need two values.
1845        // For simplicity, use the same approach: each channel tree has
1846        // a simple code.
1847
1848        // Collect unique values per channel.
1849        let greens: Vec<u8> = pixels.iter().map(|p| ((p >> 8) & 0xFF) as u8).collect();
1850        let reds: Vec<u8> = pixels.iter().map(|p| ((p >> 16) & 0xFF) as u8).collect();
1851        let blues: Vec<u8> = pixels.iter().map(|p| (p & 0xFF) as u8).collect();
1852        let alphas: Vec<u8> = pixels.iter().map(|p| ((p >> 24) & 0xFF) as u8).collect();
1853
1854        // For this test, use uniform color so each tree is single-symbol.
1855        // Verify all channels are uniform.
1856        let g = greens[0];
1857        let r = reds[0];
1858        let b = blues[0];
1859        let a = alphas[0];
1860        assert!(
1861            greens.iter().all(|&v| v == g),
1862            "Non-uniform green channel in test helper"
1863        );
1864        assert!(
1865            reds.iter().all(|&v| v == r),
1866            "Non-uniform red channel in test helper"
1867        );
1868        assert!(
1869            blues.iter().all(|&v| v == b),
1870            "Non-uniform blue channel in test helper"
1871        );
1872        assert!(
1873            alphas.iter().all(|&v| v == a),
1874            "Non-uniform alpha channel in test helper"
1875        );
1876
1877        let mut bits = BitWriter::new();
1878
1879        // No transforms.
1880        bits.write(0, 1);
1881        // No color cache.
1882        bits.write(0, 1);
1883        // No meta-Huffman.
1884        bits.write(0, 1);
1885
1886        // Five single-symbol trees.
1887        write_single_symbol_tree(&mut bits, u16::from(g));
1888        write_single_symbol_tree(&mut bits, u16::from(r));
1889        write_single_symbol_tree(&mut bits, u16::from(b));
1890        write_single_symbol_tree(&mut bits, u16::from(a));
1891        write_single_symbol_tree(&mut bits, 0);
1892
1893        let body = bits.finish();
1894
1895        // Header for 2x2 image.
1896        let val: u32 = 1 | (1 << 14); // width-1=1, height-1=1
1897        let val = val | if a != 255 { 1 << 28 } else { 0 };
1898        let mut data = vec![VP8L_SIGNATURE];
1899        data.extend_from_slice(&val.to_le_bytes());
1900        data.extend_from_slice(&body);
1901        data
1902    }
1903
1904    #[test]
1905    fn test_decode_2x2_uniform() {
1906        let color = 0xFF336699u32;
1907        let data = build_2x2_bitstream([color; 4]);
1908        let mut decoder = Vp8lDecoder::new();
1909        let result = decoder.decode(&data).expect("should decode");
1910        assert_eq!(result.width, 2);
1911        assert_eq!(result.height, 2);
1912        assert_eq!(result.pixels.len(), 4);
1913        for p in &result.pixels {
1914            assert_eq!(*p, color);
1915        }
1916    }
1917}