1use crate::error::{CodecError, CodecResult};
16
17const VP8L_SIGNATURE: u8 = 0x2f;
23
24const VP8L_MAX_DIMENSION: u32 = 16384;
26
27const CODE_LENGTH_CODE_ORDER: [usize; 19] = [
29 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
30];
31
32const MAX_HUFFMAN_CODE_LENGTH: u32 = 15;
34
35const NUM_CODE_LENGTH_CODES: usize = 19;
37
38const TRANSFORM_PREDICTOR: u32 = 0;
40const TRANSFORM_SUBTRACT_GREEN: u32 = 2;
41
42const HUFFMAN_CODES_PER_META_CODE: usize = 5;
49
50const GREEN_ALPHABET_SIZE: usize = 280;
53
54const CHANNEL_ALPHABET_SIZE: usize = 256;
56
57const DISTANCE_ALPHABET_SIZE: usize = 40;
59
60#[derive(Debug)]
69pub struct Vp8lBitWriter {
70 data: Vec<u8>,
72 bits: u64,
74 num_bits: u32,
76}
77
78impl Vp8lBitWriter {
79 pub fn new() -> Self {
81 Self {
82 data: Vec::with_capacity(4096),
83 bits: 0,
84 num_bits: 0,
85 }
86 }
87
88 pub fn with_capacity(capacity: usize) -> Self {
90 Self {
91 data: Vec::with_capacity(capacity),
92 bits: 0,
93 num_bits: 0,
94 }
95 }
96
97 pub fn put_bits(&mut self, value: u32, n_bits: u32) {
99 debug_assert!(n_bits <= 32);
100 debug_assert!(n_bits == 32 || value < (1u32 << n_bits));
101
102 self.bits |= (value as u64) << self.num_bits;
103 self.num_bits += n_bits;
104 self.flush_partial();
105 }
106
107 pub fn put_bit(&mut self, bit: bool) {
109 self.put_bits(u32::from(bit), 1);
110 }
111
112 fn flush_partial(&mut self) {
114 while self.num_bits >= 8 {
115 self.data.push((self.bits & 0xff) as u8);
116 self.bits >>= 8;
117 self.num_bits -= 8;
118 }
119 }
120
121 pub fn finish(mut self) -> Vec<u8> {
124 if self.num_bits > 0 {
125 self.data.push((self.bits & 0xff) as u8);
126 }
127 self.data
128 }
129
130 pub fn byte_len(&self) -> usize {
133 self.data.len() + if self.num_bits > 0 { 1 } else { 0 }
134 }
135}
136
137#[derive(Debug, Clone, Copy, Default)]
143struct HuffmanCode {
144 len: u32,
146 code: u32,
148}
149
150#[derive(Debug, Clone)]
152struct Histogram {
153 counts: Vec<u32>,
154}
155
156impl Histogram {
157 fn new(size: usize) -> Self {
158 Self {
159 counts: vec![0; size],
160 }
161 }
162
163 fn add(&mut self, symbol: usize) {
164 if symbol < self.counts.len() {
165 self.counts[symbol] += 1;
166 }
167 }
168
169 fn alphabet_size(&self) -> usize {
170 self.counts.len()
171 }
172
173 fn num_used(&self) -> usize {
175 self.counts.iter().filter(|&&c| c > 0).count()
176 }
177
178 fn single_symbol(&self) -> Option<usize> {
180 if self.num_used() == 1 {
181 self.counts.iter().position(|&c| c > 0)
182 } else {
183 None
184 }
185 }
186}
187
188fn build_huffman_codes(hist: &Histogram) -> CodecResult<Vec<HuffmanCode>> {
193 let n = hist.alphabet_size();
194 let mut codes = vec![HuffmanCode::default(); n];
195
196 let used = hist.num_used();
197 if used == 0 {
198 return Ok(codes);
200 }
201 if used == 1 {
202 if let Some(sym) = hist.single_symbol() {
204 codes[sym] = HuffmanCode { len: 1, code: 0 };
205 }
206 return Ok(codes);
207 }
208 if used == 2 {
209 let mut iter = hist
211 .counts
212 .iter()
213 .enumerate()
214 .filter(|(_, &c)| c > 0)
215 .map(|(i, _)| i);
216 if let (Some(a), Some(b)) = (iter.next(), iter.next()) {
217 codes[a] = HuffmanCode { len: 1, code: 0 };
218 codes[b] = HuffmanCode { len: 1, code: 1 };
219 }
220 return Ok(codes);
221 }
222
223 let code_lengths = build_code_lengths(&hist.counts, MAX_HUFFMAN_CODE_LENGTH)?;
225
226 assign_canonical_codes(&code_lengths, &mut codes);
228
229 Ok(codes)
230}
231
232fn build_code_lengths(counts: &[u32], max_length: u32) -> CodecResult<Vec<u32>> {
234 let n = counts.len();
235 let mut lengths = vec![0u32; n];
236
237 let mut symbols: Vec<(u32, usize)> = counts
239 .iter()
240 .enumerate()
241 .filter(|(_, &c)| c > 0)
242 .map(|(i, &c)| (c, i))
243 .collect();
244
245 if symbols.len() < 2 {
246 for &(_, sym) in &symbols {
247 lengths[sym] = 1;
248 }
249 return Ok(lengths);
250 }
251
252 symbols.sort_by(|a, b| a.0.cmp(&b.0).then(a.1.cmp(&b.1)));
254
255 let tree_lengths = build_tree_lengths(&symbols, max_length);
257
258 for (i, &(_, sym)) in symbols.iter().enumerate() {
259 lengths[sym] = tree_lengths[i];
260 }
261
262 Ok(lengths)
263}
264
265fn build_tree_lengths(symbols: &[(u32, usize)], max_length: u32) -> Vec<u32> {
270 let n = symbols.len();
271 if n <= 1 {
272 return vec![1; n];
273 }
274
275 let mut nodes: Vec<(u64, Option<usize>, Option<usize>)> = symbols
278 .iter()
279 .map(|&(freq, _)| (freq.max(1) as u64, None, None))
280 .collect();
281
282 let mut active: Vec<usize> = (0..n).collect();
283
284 while active.len() > 1 {
285 active.sort_by(|&a, &b| nodes[a].0.cmp(&nodes[b].0));
287 let left = active[0];
288 let right = active[1];
289
290 let merged_freq = nodes[left].0 + nodes[right].0;
291 let new_idx = nodes.len();
292 nodes.push((merged_freq, Some(left), Some(right)));
293
294 active = active[2..].to_vec();
296 active.push(new_idx);
297 }
298
299 let mut depths = vec![0u32; n];
301 if let Some(&root) = active.first() {
302 compute_depths(&nodes, root, 0, n, &mut depths);
303 }
304
305 limit_code_lengths(&mut depths, max_length);
307
308 depths
309}
310
311fn compute_depths(
313 nodes: &[(u64, Option<usize>, Option<usize>)],
314 node_idx: usize,
315 depth: u32,
316 num_leaves: usize,
317 depths: &mut [u32],
318) {
319 if node_idx < num_leaves {
320 depths[node_idx] = depth.max(1);
322 return;
323 }
324 let (_, left, right) = nodes[node_idx];
325 if let Some(l) = left {
326 compute_depths(nodes, l, depth + 1, num_leaves, depths);
327 }
328 if let Some(r) = right {
329 compute_depths(nodes, r, depth + 1, num_leaves, depths);
330 }
331}
332
333fn limit_code_lengths(depths: &mut [u32], max_length: u32) {
338 let mut any_over = false;
339 for d in depths.iter() {
340 if *d > max_length {
341 any_over = true;
342 break;
343 }
344 }
345 if !any_over {
346 return;
347 }
348
349 for d in depths.iter_mut() {
351 if *d > max_length {
352 *d = max_length;
353 }
354 }
355
356 for _ in 0..1000 {
358 let kraft_sum: u64 = depths
359 .iter()
360 .filter(|&&d| d > 0)
361 .map(|&d| 1u64 << (max_length - d))
362 .sum();
363
364 let target = 1u64 << max_length;
365
366 if kraft_sum == target {
367 break;
368 }
369
370 if kraft_sum > target {
371 if let Some(pos) = depths
373 .iter()
374 .enumerate()
375 .filter(|(_, &d)| d > 0 && d < max_length)
376 .min_by_key(|(_, &d)| d)
377 .map(|(i, _)| i)
378 {
379 depths[pos] += 1;
380 } else {
381 break;
382 }
383 } else {
384 if let Some(pos) = depths
386 .iter()
387 .enumerate()
388 .filter(|(_, &d)| d == max_length)
389 .max_by_key(|(i, _)| *i)
390 .map(|(i, _)| i)
391 {
392 depths[pos] -= 1;
393 } else {
394 break;
395 }
396 }
397 }
398}
399
400fn assign_canonical_codes(lengths: &[u32], codes: &mut [HuffmanCode]) {
406 let max_len = lengths.iter().copied().max().unwrap_or(0);
407 if max_len == 0 {
408 return;
409 }
410
411 let mut bl_count = vec![0u32; (max_len + 1) as usize];
413 for &l in lengths {
414 if l > 0 {
415 bl_count[l as usize] += 1;
416 }
417 }
418
419 let mut next_code = vec![0u32; (max_len + 1) as usize];
421 let mut code = 0u32;
422 for bits in 1..=max_len {
423 code = (code + bl_count[(bits - 1) as usize]) << 1;
424 next_code[bits as usize] = code;
425 }
426
427 for (sym, &len) in lengths.iter().enumerate() {
429 if len > 0 {
430 let c = next_code[len as usize];
431 next_code[len as usize] += 1;
432 codes[sym] = HuffmanCode {
433 len,
434 code: reverse_bits(c, len),
435 };
436 }
437 }
438}
439
440fn reverse_bits(value: u32, num_bits: u32) -> u32 {
442 let mut result = 0u32;
443 let mut v = value;
444 for _ in 0..num_bits {
445 result = (result << 1) | (v & 1);
446 v >>= 1;
447 }
448 result
449}
450
451fn apply_subtract_green(pixels: &mut [u32]) {
462 for px in pixels.iter_mut() {
463 let a = (*px >> 24) & 0xff;
464 let r = (*px >> 16) & 0xff;
465 let g = (*px >> 8) & 0xff;
466 let b = *px & 0xff;
467
468 let new_r = r.wrapping_sub(g) & 0xff;
469 let new_b = b.wrapping_sub(g) & 0xff;
470
471 *px = (a << 24) | (new_r << 16) | (g << 8) | new_b;
472 }
473}
474
475fn apply_predictor_transform(pixels: &mut [u32], width: u32, height: u32) -> CodecResult<Vec<u8>> {
483 let w = width as usize;
484 let h = height as usize;
485
486 if pixels.len() != w * h {
487 return Err(CodecError::InvalidParameter(format!(
488 "pixel count {} != width {} * height {}",
489 pixels.len(),
490 w,
491 h
492 )));
493 }
494
495 let tile_size = 1usize << 3;
498 let tiles_x = (w + tile_size - 1) / tile_size;
499 let tiles_y = (h + tile_size - 1) / tile_size;
500
501 let predictor_mode: u8 = 1;
503 let predictor_data = vec![predictor_mode; tiles_x * tiles_y];
504
505 let original = pixels.to_vec();
507
508 for y in 0..h {
509 for x in 0..w {
510 let idx = y * w + x;
511 let current = original[idx];
512
513 let predicted = if x == 0 && y == 0 {
514 0xff000000u32
516 } else if x == 0 {
517 original[(y - 1) * w + x]
519 } else {
520 original[y * w + (x - 1)]
522 };
523
524 let ca = (current >> 24) & 0xff;
525 let cr = (current >> 16) & 0xff;
526 let cg = (current >> 8) & 0xff;
527 let cb = current & 0xff;
528
529 let pa = (predicted >> 24) & 0xff;
530 let pr = (predicted >> 16) & 0xff;
531 let pg = (predicted >> 8) & 0xff;
532 let pb = predicted & 0xff;
533
534 let ra = ca.wrapping_sub(pa) & 0xff;
535 let rr = cr.wrapping_sub(pr) & 0xff;
536 let rg = cg.wrapping_sub(pg) & 0xff;
537 let rb = cb.wrapping_sub(pb) & 0xff;
538
539 pixels[idx] = (ra << 24) | (rr << 16) | (rg << 8) | rb;
540 }
541 }
542
543 Ok(predictor_data)
544}
545
546fn build_histograms(pixels: &[u32]) -> [Histogram; HUFFMAN_CODES_PER_META_CODE] {
552 let mut histograms = [
553 Histogram::new(GREEN_ALPHABET_SIZE),
554 Histogram::new(CHANNEL_ALPHABET_SIZE),
555 Histogram::new(CHANNEL_ALPHABET_SIZE),
556 Histogram::new(CHANNEL_ALPHABET_SIZE),
557 Histogram::new(DISTANCE_ALPHABET_SIZE),
558 ];
559
560 for &px in pixels {
561 let g = ((px >> 8) & 0xff) as usize;
562 let r = ((px >> 16) & 0xff) as usize;
563 let b = (px & 0xff) as usize;
564 let a = ((px >> 24) & 0xff) as usize;
565
566 histograms[0].add(g);
567 histograms[1].add(r);
568 histograms[2].add(b);
569 histograms[3].add(a);
570 }
572
573 histograms
574}
575
576fn write_huffman_symbol(writer: &mut Vp8lBitWriter, codes: &[HuffmanCode], symbol: usize) {
578 let hc = if symbol < codes.len() {
579 codes[symbol]
580 } else {
581 HuffmanCode { len: 1, code: 0 }
582 };
583 if hc.len > 0 {
584 writer.put_bits(hc.code, hc.len);
585 }
586}
587
588fn write_huffman_codes(
595 writer: &mut Vp8lBitWriter,
596 codes: &[HuffmanCode],
597 alphabet_size: usize,
598) -> CodecResult<()> {
599 let num_used = codes.iter().filter(|c| c.len > 0).count();
600
601 if num_used <= 2 {
603 return write_simple_code(writer, codes, num_used);
604 }
605
606 write_normal_code(writer, codes, alphabet_size)
608}
609
610fn write_simple_code(
622 writer: &mut Vp8lBitWriter,
623 codes: &[HuffmanCode],
624 num_used: usize,
625) -> CodecResult<()> {
626 writer.put_bit(true);
628
629 let symbols: Vec<usize> = codes
630 .iter()
631 .enumerate()
632 .filter(|(_, c)| c.len > 0)
633 .map(|(i, _)| i)
634 .collect();
635
636 if num_used == 0 {
637 writer.put_bit(false); writer.put_bit(false); writer.put_bits(0, 1);
641 return Ok(());
642 }
643
644 if num_used == 1 {
645 let sym = symbols[0];
646 writer.put_bit(false); if sym < 2 {
648 writer.put_bit(false); writer.put_bits(sym as u32, 1);
650 } else {
651 writer.put_bit(true); writer.put_bits(sym as u32, 8);
653 }
654 } else {
655 let sym0 = symbols[0];
657 let sym1 = symbols[1];
658 writer.put_bit(true); writer.put_bits(sym0 as u32, 8);
660 writer.put_bits(sym1 as u32, 8);
661 }
662
663 Ok(())
664}
665
666fn write_normal_code(
668 writer: &mut Vp8lBitWriter,
669 codes: &[HuffmanCode],
670 alphabet_size: usize,
671) -> CodecResult<()> {
672 writer.put_bit(false);
674
675 let mut code_lengths: Vec<u32> = codes.iter().take(alphabet_size).map(|c| c.len).collect();
677 code_lengths.resize(alphabet_size, 0);
678
679 let rle_symbols = rle_encode_code_lengths(&code_lengths);
681
682 let mut cl_hist = Histogram::new(NUM_CODE_LENGTH_CODES);
684 for &(sym, _) in &rle_symbols {
685 cl_hist.add(sym as usize);
686 }
687
688 let cl_codes = build_huffman_codes(&cl_hist)?;
690
691 let mut num_cl_codes = 4usize; for i in (0..NUM_CODE_LENGTH_CODES).rev() {
694 let sym = CODE_LENGTH_CODE_ORDER[i];
695 if sym < cl_codes.len() && cl_codes[sym].len > 0 {
696 num_cl_codes = i + 1;
697 break;
698 }
699 }
700 num_cl_codes = num_cl_codes.max(4);
701
702 writer.put_bits((num_cl_codes - 4) as u32, 4);
704
705 for i in 0..num_cl_codes {
707 let sym = CODE_LENGTH_CODE_ORDER[i];
708 let len = if sym < cl_codes.len() {
709 cl_codes[sym].len
710 } else {
711 0
712 };
713 writer.put_bits(len, 3);
714 }
715
716 for &(sym, extra) in &rle_symbols {
718 write_huffman_symbol(writer, &cl_codes, sym as usize);
719 match sym {
720 16 => {
721 writer.put_bits(extra, 2);
723 }
724 17 => {
725 writer.put_bits(extra, 3);
727 }
728 18 => {
729 writer.put_bits(extra, 7);
731 }
732 _ => {
733 }
735 }
736 }
737
738 Ok(())
739}
740
741fn rle_encode_code_lengths(lengths: &[u32]) -> Vec<(u32, u32)> {
748 let mut result = Vec::new();
749 let mut i = 0;
750
751 while i < lengths.len() {
752 let val = lengths[i];
753
754 if val == 0 {
755 let mut run = 1;
757 while i + run < lengths.len() && lengths[i + run] == 0 {
758 run += 1;
759 }
760
761 let mut remaining = run;
762 while remaining > 0 {
763 if remaining >= 11 {
764 let count = remaining.min(138);
765 result.push((18, (count - 11) as u32));
766 remaining -= count;
767 } else if remaining >= 3 {
768 let count = remaining.min(10);
769 result.push((17, (count - 3) as u32));
770 remaining -= count;
771 } else {
772 result.push((0, 0));
773 remaining -= 1;
774 }
775 }
776
777 i += run;
778 } else {
779 result.push((val, 0));
781 i += 1;
782
783 let mut run = 0;
785 while i + run < lengths.len() && lengths[i + run] == val {
786 run += 1;
787 }
788
789 let mut remaining = run;
790 while remaining >= 3 {
791 let count = remaining.min(6);
792 result.push((16, (count - 3) as u32));
793 remaining -= count;
794 }
795 while remaining > 0 {
796 result.push((val, 0));
797 remaining -= 1;
798 }
799
800 i += run;
801 }
802 }
803
804 result
805}
806
807pub struct Vp8lEncoder {
827 effort: u8,
830}
831
832impl Vp8lEncoder {
833 pub fn new(effort: u8) -> Self {
838 Self {
839 effort: effort.min(100),
840 }
841 }
842
843 pub fn encode(
857 &self,
858 pixels: &[u32],
859 width: u32,
860 height: u32,
861 has_alpha: bool,
862 ) -> CodecResult<Vec<u8>> {
863 self.validate_inputs(pixels, width, height)?;
864
865 let mut transformed = pixels.to_vec();
867
868 let use_predictor = self.effort > 30;
870
871 let mut predictor_data: Option<(Vec<u8>, u32, u32, u32)> = None;
873
874 if use_predictor {
876 let size_bits: u32 = 3;
877 let tile_size = 1u32 << size_bits;
878 let tiles_x = (width + tile_size - 1) / tile_size;
879 let tiles_y = (height + tile_size - 1) / tile_size;
880
881 let pred_data = apply_predictor_transform(&mut transformed, width, height)?;
882 predictor_data = Some((pred_data, size_bits, tiles_x, tiles_y));
883 }
884
885 apply_subtract_green(&mut transformed);
887
888 let estimated_size = (pixels.len() * 4) + 256;
890 let mut writer = Vp8lBitWriter::with_capacity(estimated_size);
891
892 self.write_header(&mut writer, width, height, has_alpha)?;
894
895 self.write_transforms(&mut writer, use_predictor, &predictor_data)?;
897
898 writer.put_bit(false);
900
901 self.write_image_data(&mut writer, &transformed)?;
903
904 Ok(writer.finish())
905 }
906
907 fn validate_inputs(&self, pixels: &[u32], width: u32, height: u32) -> CodecResult<()> {
909 if width == 0 || height == 0 {
910 return Err(CodecError::InvalidParameter(
911 "width and height must be > 0".to_string(),
912 ));
913 }
914 if width > VP8L_MAX_DIMENSION || height > VP8L_MAX_DIMENSION {
915 return Err(CodecError::InvalidParameter(format!(
916 "dimensions {}x{} exceed VP8L maximum {}",
917 width, height, VP8L_MAX_DIMENSION
918 )));
919 }
920 let expected = (width as usize) * (height as usize);
921 if pixels.len() != expected {
922 return Err(CodecError::InvalidParameter(format!(
923 "pixel count {} != expected {} ({}x{})",
924 pixels.len(),
925 expected,
926 width,
927 height
928 )));
929 }
930 Ok(())
931 }
932
933 fn write_header(
942 &self,
943 writer: &mut Vp8lBitWriter,
944 width: u32,
945 height: u32,
946 has_alpha: bool,
947 ) -> CodecResult<()> {
948 writer.put_bits(u32::from(VP8L_SIGNATURE), 8);
950
951 writer.put_bits(width - 1, 14);
953
954 writer.put_bits(height - 1, 14);
956
957 writer.put_bit(has_alpha);
959
960 writer.put_bits(0, 3);
962
963 Ok(())
964 }
965
966 fn write_transforms(
972 &self,
973 writer: &mut Vp8lBitWriter,
974 use_predictor: bool,
975 predictor_data: &Option<(Vec<u8>, u32, u32, u32)>,
976 ) -> CodecResult<()> {
977 writer.put_bit(true); writer.put_bits(TRANSFORM_SUBTRACT_GREEN, 2);
980 if use_predictor {
984 if let Some((ref pred_data, size_bits, _tiles_x, _tiles_y)) = *predictor_data {
985 writer.put_bit(true); writer.put_bits(TRANSFORM_PREDICTOR, 2);
987 writer.put_bits(size_bits, 3);
989
990 let pred_pixels: Vec<u32> =
993 pred_data.iter().map(|&mode| (mode as u32) << 8).collect();
994
995 self.write_image_data(writer, &pred_pixels)?;
996 }
997 }
998
999 Ok(())
1000 }
1001
1002 fn write_image_data(&self, writer: &mut Vp8lBitWriter, pixels: &[u32]) -> CodecResult<()> {
1011 writer.put_bit(false);
1013
1014 writer.put_bit(false);
1017
1018 let histograms = build_histograms(pixels);
1020
1021 let alphabet_sizes = [
1023 GREEN_ALPHABET_SIZE,
1024 CHANNEL_ALPHABET_SIZE,
1025 CHANNEL_ALPHABET_SIZE,
1026 CHANNEL_ALPHABET_SIZE,
1027 DISTANCE_ALPHABET_SIZE,
1028 ];
1029
1030 let mut all_codes: Vec<Vec<HuffmanCode>> = Vec::with_capacity(HUFFMAN_CODES_PER_META_CODE);
1031
1032 for (i, hist) in histograms.iter().enumerate() {
1033 let codes = build_huffman_codes(hist)?;
1034 write_huffman_codes(writer, &codes, alphabet_sizes[i])?;
1035 all_codes.push(codes);
1036 }
1037
1038 for &px in pixels {
1040 let g = ((px >> 8) & 0xff) as usize;
1041 let r = ((px >> 16) & 0xff) as usize;
1042 let b = (px & 0xff) as usize;
1043 let a = ((px >> 24) & 0xff) as usize;
1044
1045 write_huffman_symbol(writer, &all_codes[0], g);
1046 write_huffman_symbol(writer, &all_codes[1], r);
1047 write_huffman_symbol(writer, &all_codes[2], b);
1048 write_huffman_symbol(writer, &all_codes[3], a);
1049 }
1050
1051 Ok(())
1052 }
1053}
1054
1055#[cfg(test)]
1060mod tests {
1061 use super::*;
1062
1063 #[test]
1066 fn test_bit_writer_basic() {
1067 let mut w = Vp8lBitWriter::new();
1068 w.put_bits(0b101, 3);
1069 w.put_bits(0b1100, 4);
1070 w.put_bit(true);
1071 let data = w.finish();
1072 assert_eq!(data.len(), 1);
1075 assert_eq!(data[0], 0xe5);
1076 }
1077
1078 #[test]
1079 fn test_bit_writer_multi_byte() {
1080 let mut w = Vp8lBitWriter::new();
1081 w.put_bits(0xff, 8);
1082 w.put_bits(0x00, 8);
1083 w.put_bits(0xab, 8);
1084 let data = w.finish();
1085 assert_eq!(data, vec![0xff, 0x00, 0xab]);
1086 }
1087
1088 #[test]
1089 fn test_bit_writer_empty() {
1090 let w = Vp8lBitWriter::new();
1091 let data = w.finish();
1092 assert!(data.is_empty());
1093 }
1094
1095 #[test]
1096 fn test_bit_writer_single_bit() {
1097 let mut w = Vp8lBitWriter::new();
1098 w.put_bit(true);
1099 let data = w.finish();
1100 assert_eq!(data, vec![0x01]);
1101 }
1102
1103 #[test]
1104 fn test_bit_writer_byte_len() {
1105 let mut w = Vp8lBitWriter::new();
1106 assert_eq!(w.byte_len(), 0);
1107 w.put_bits(0xff, 8);
1108 assert_eq!(w.byte_len(), 1);
1109 w.put_bit(true);
1110 assert_eq!(w.byte_len(), 2);
1111 }
1112
1113 #[test]
1116 fn test_reverse_bits() {
1117 assert_eq!(reverse_bits(0b110, 3), 0b011);
1118 assert_eq!(reverse_bits(0b1010, 4), 0b0101);
1119 assert_eq!(reverse_bits(0b1, 1), 0b1);
1120 assert_eq!(reverse_bits(0b0, 1), 0b0);
1121 assert_eq!(reverse_bits(0b11001, 5), 0b10011);
1122 }
1123
1124 #[test]
1127 fn test_subtract_green() {
1128 let mut pixels = vec![0xff_80_40_c0u32];
1130 apply_subtract_green(&mut pixels);
1131
1132 let a = (pixels[0] >> 24) & 0xff;
1133 let r = (pixels[0] >> 16) & 0xff;
1134 let g = (pixels[0] >> 8) & 0xff;
1135 let b = pixels[0] & 0xff;
1136
1137 assert_eq!(a, 0xff);
1138 assert_eq!(g, 0x40);
1139 assert_eq!(r, (0x80u32.wrapping_sub(0x40)) & 0xff);
1140 assert_eq!(b, (0xc0u32.wrapping_sub(0x40)) & 0xff);
1141 }
1142
1143 #[test]
1144 fn test_subtract_green_wraparound() {
1145 let mut pixels = vec![0xff_10_80_20u32];
1147 apply_subtract_green(&mut pixels);
1148 let r = (pixels[0] >> 16) & 0xff;
1149 assert_eq!(r, 0x90);
1150 }
1151
1152 #[test]
1155 fn test_histogram_basic() {
1156 let mut hist = Histogram::new(256);
1157 hist.add(0);
1158 hist.add(0);
1159 hist.add(1);
1160 hist.add(255);
1161
1162 assert_eq!(hist.num_used(), 3);
1163 assert_eq!(hist.counts[0], 2);
1164 assert_eq!(hist.counts[1], 1);
1165 assert_eq!(hist.counts[255], 1);
1166 }
1167
1168 #[test]
1169 fn test_histogram_single_symbol() {
1170 let mut hist = Histogram::new(256);
1171 hist.add(42);
1172 hist.add(42);
1173 hist.add(42);
1174
1175 assert_eq!(hist.num_used(), 1);
1176 assert_eq!(hist.single_symbol(), Some(42));
1177 }
1178
1179 #[test]
1180 fn test_histogram_out_of_range() {
1181 let mut hist = Histogram::new(10);
1182 hist.add(100); assert_eq!(hist.num_used(), 0);
1184 }
1185
1186 #[test]
1189 fn test_build_huffman_empty() {
1190 let hist = Histogram::new(256);
1191 let codes = build_huffman_codes(&hist).expect("should build");
1192 assert!(codes.iter().all(|c| c.len == 0));
1193 }
1194
1195 #[test]
1196 fn test_build_huffman_single_symbol() {
1197 let mut hist = Histogram::new(256);
1198 hist.add(100);
1199 hist.add(100);
1200
1201 let codes = build_huffman_codes(&hist).expect("should build");
1202 assert_eq!(codes[100].len, 1);
1203 assert_eq!(codes[100].code, 0);
1204 }
1205
1206 #[test]
1207 fn test_build_huffman_two_symbols() {
1208 let mut hist = Histogram::new(256);
1209 hist.add(10);
1210 hist.add(20);
1211
1212 let codes = build_huffman_codes(&hist).expect("should build");
1213 assert_eq!(codes[10].len, 1);
1214 assert_eq!(codes[20].len, 1);
1215 assert_ne!(codes[10].code, codes[20].code);
1216 }
1217
1218 #[test]
1219 fn test_build_huffman_multiple_symbols() {
1220 let mut hist = Histogram::new(256);
1221 for _ in 0..100 {
1222 hist.add(0);
1223 }
1224 for _ in 0..50 {
1225 hist.add(1);
1226 }
1227 for _ in 0..25 {
1228 hist.add(2);
1229 }
1230 for _ in 0..10 {
1231 hist.add(3);
1232 }
1233
1234 let codes = build_huffman_codes(&hist).expect("should build");
1235
1236 assert!(codes[0].len <= codes[3].len);
1238 for i in 0..4 {
1239 assert!(codes[i].len > 0, "symbol {} should have nonzero length", i);
1240 assert!(
1241 codes[i].len <= MAX_HUFFMAN_CODE_LENGTH,
1242 "symbol {} code length {} exceeds max",
1243 i,
1244 codes[i].len
1245 );
1246 }
1247 }
1248
1249 #[test]
1250 fn test_build_huffman_all_equal_frequencies() {
1251 let mut hist = Histogram::new(4);
1252 for i in 0..4 {
1253 hist.add(i);
1254 }
1255
1256 let codes = build_huffman_codes(&hist).expect("should build");
1257 for i in 0..4 {
1259 assert_eq!(codes[i].len, 2, "symbol {} should have length 2", i);
1260 }
1261 }
1262
1263 #[test]
1264 fn test_canonical_codes_prefix_free() {
1265 let mut hist = Histogram::new(8);
1266 hist.add(0);
1267 hist.add(0);
1268 hist.add(0);
1269 hist.add(0);
1270 hist.add(1);
1271 hist.add(1);
1272 hist.add(2);
1273 hist.add(3);
1274
1275 let codes = build_huffman_codes(&hist).expect("should build");
1276
1277 let used: Vec<(usize, &HuffmanCode)> = codes
1279 .iter()
1280 .enumerate()
1281 .filter(|(_, c)| c.len > 0)
1282 .collect();
1283
1284 for i in 0..used.len() {
1285 for j in (i + 1)..used.len() {
1286 let (_, ci) = used[i];
1287 let (_, cj) = used[j];
1288 let min_len = ci.len.min(cj.len);
1289 let mask = (1u32 << min_len) - 1;
1290 if ci.len != cj.len {
1291 assert_ne!(ci.code & mask, cj.code & mask, "codes are not prefix-free");
1292 } else {
1293 assert_ne!(ci.code, cj.code, "duplicate codes");
1294 }
1295 }
1296 }
1297 }
1298
1299 #[test]
1302 fn test_rle_encode_zeros() {
1303 let lengths = vec![0; 20];
1304 let rle = rle_encode_code_lengths(&lengths);
1305 assert_eq!(rle.len(), 1);
1306 assert_eq!(rle[0].0, 18); assert_eq!(rle[0].1, (20 - 11) as u32);
1308 }
1309
1310 #[test]
1311 fn test_rle_encode_small_zeros() {
1312 let lengths = vec![0, 0, 0, 0, 0];
1313 let rle = rle_encode_code_lengths(&lengths);
1314 assert_eq!(rle.len(), 1);
1315 assert_eq!(rle[0].0, 17); assert_eq!(rle[0].1, (5 - 3) as u32);
1317 }
1318
1319 #[test]
1320 fn test_rle_encode_mixed() {
1321 let lengths = vec![3, 3, 3, 3, 0, 0, 0, 5];
1322 let rle = rle_encode_code_lengths(&lengths);
1323 assert!(rle.len() >= 3);
1324 assert_eq!(rle[0].0, 3); assert_eq!(rle[1].0, 16); }
1327
1328 #[test]
1329 fn test_rle_encode_single_values() {
1330 let lengths = vec![1, 2, 3, 4, 5];
1331 let rle = rle_encode_code_lengths(&lengths);
1332 assert_eq!(rle.len(), 5);
1334 for (i, &(sym, _)) in rle.iter().enumerate() {
1335 assert_eq!(sym, (i + 1) as u32);
1336 }
1337 }
1338
1339 #[test]
1342 fn test_limit_code_lengths() {
1343 let mut depths = vec![1, 2, 16, 16, 16];
1344 limit_code_lengths(&mut depths, 8);
1345 for &d in &depths {
1346 assert!(d <= 8, "depth {} exceeds max 8", d);
1347 }
1348 }
1349
1350 #[test]
1351 fn test_limit_code_lengths_no_change() {
1352 let original = vec![1, 2, 3, 4, 5];
1353 let mut depths = original.clone();
1354 limit_code_lengths(&mut depths, 15);
1355 assert_eq!(depths, original);
1356 }
1357
1358 #[test]
1361 fn test_header_signature() {
1362 let encoder = Vp8lEncoder::new(0);
1363 let mut writer = Vp8lBitWriter::new();
1364 encoder
1365 .write_header(&mut writer, 100, 200, true)
1366 .expect("header should write");
1367 let data = writer.finish();
1368 assert_eq!(data[0], VP8L_SIGNATURE);
1369 }
1370
1371 #[test]
1372 fn test_header_dimensions_encoded() {
1373 let encoder = Vp8lEncoder::new(0);
1374 let mut writer = Vp8lBitWriter::new();
1375 encoder
1376 .write_header(&mut writer, 100, 200, false)
1377 .expect("write header");
1378 let data = writer.finish();
1379
1380 assert_eq!(data[0], 0x2f);
1381
1382 let val = (data[1] as u32)
1384 | ((data[2] as u32) << 8)
1385 | ((data[3] as u32) << 16)
1386 | ((data[4] as u32) << 24);
1387
1388 let w_minus_1 = val & 0x3fff;
1389 let h_minus_1 = (val >> 14) & 0x3fff;
1390 let alpha_used = (val >> 28) & 1;
1391 let version = (val >> 29) & 0x7;
1392
1393 assert_eq!(w_minus_1, 99);
1394 assert_eq!(h_minus_1, 199);
1395 assert_eq!(alpha_used, 0);
1396 assert_eq!(version, 0);
1397 }
1398
1399 #[test]
1400 fn test_header_with_alpha() {
1401 let encoder = Vp8lEncoder::new(0);
1402 let mut writer = Vp8lBitWriter::new();
1403 encoder
1404 .write_header(&mut writer, 50, 75, true)
1405 .expect("write header");
1406 let data = writer.finish();
1407
1408 let val = (data[1] as u32)
1409 | ((data[2] as u32) << 8)
1410 | ((data[3] as u32) << 16)
1411 | ((data[4] as u32) << 24);
1412
1413 let alpha_used = (val >> 28) & 1;
1414 assert_eq!(alpha_used, 1);
1415 }
1416
1417 #[test]
1420 fn test_encoder_1x1_image() {
1421 let encoder = Vp8lEncoder::new(0);
1422 let pixels = vec![0xff_80_40_20u32];
1423 let result = encoder.encode(&pixels, 1, 1, true);
1424 assert!(result.is_ok());
1425 let data = result.expect("encode should succeed");
1426 assert_eq!(data[0], VP8L_SIGNATURE);
1427 }
1428
1429 #[test]
1430 fn test_encoder_small_image() {
1431 let encoder = Vp8lEncoder::new(0);
1432 let pixels = vec![0xff_ff_00_00u32; 4]; let result = encoder.encode(&pixels, 2, 2, false);
1434 assert!(result.is_ok());
1435 let data = result.expect("encode should succeed");
1436 assert_eq!(data[0], VP8L_SIGNATURE);
1437 assert!(data.len() > 5);
1438 }
1439
1440 #[test]
1441 fn test_encoder_with_alpha() {
1442 let encoder = Vp8lEncoder::new(0);
1443 let pixels = vec![0x80_00_ff_00u32; 16]; let result = encoder.encode(&pixels, 4, 4, true);
1445 assert!(result.is_ok());
1446 }
1447
1448 #[test]
1449 fn test_encoder_all_black() {
1450 let encoder = Vp8lEncoder::new(0);
1451 let pixels = vec![0xff_00_00_00u32; 64];
1452 let result = encoder.encode(&pixels, 8, 8, false);
1453 assert!(result.is_ok());
1454 }
1455
1456 #[test]
1457 fn test_encoder_gradient() {
1458 let encoder = Vp8lEncoder::new(0);
1459 let mut pixels = Vec::with_capacity(256);
1460 for i in 0..256u32 {
1461 pixels.push(0xff_00_00_00 | (i << 16) | (i << 8) | i);
1462 }
1463 let result = encoder.encode(&pixels, 16, 16, false);
1464 assert!(result.is_ok());
1465 }
1466
1467 #[test]
1468 fn test_encoder_with_predictor() {
1469 let encoder = Vp8lEncoder::new(50); let pixels = vec![0xff_ff_00_00u32; 64];
1471 let result = encoder.encode(&pixels, 8, 8, false);
1472 assert!(result.is_ok());
1473 }
1474
1475 #[test]
1476 fn test_encoder_invalid_zero_dimensions() {
1477 let encoder = Vp8lEncoder::new(0);
1478 let pixels = vec![0u32; 4];
1479
1480 assert!(encoder.encode(&pixels, 0, 2, false).is_err());
1481 assert!(encoder.encode(&pixels, 2, 0, false).is_err());
1482 }
1483
1484 #[test]
1485 fn test_encoder_dimension_overflow() {
1486 let encoder = Vp8lEncoder::new(0);
1487 let pixels = vec![0u32; 1];
1488 let result = encoder.encode(&pixels, VP8L_MAX_DIMENSION + 1, 1, false);
1489 assert!(result.is_err());
1490 }
1491
1492 #[test]
1493 fn test_encoder_pixel_count_mismatch() {
1494 let encoder = Vp8lEncoder::new(0);
1495 let pixels = vec![0u32; 10];
1496 let result = encoder.encode(&pixels, 4, 4, false);
1497 assert!(result.is_err());
1498 }
1499
1500 #[test]
1501 fn test_encoder_large_uniform_compresses() {
1502 let encoder = Vp8lEncoder::new(0);
1503 let pixels = vec![0xff_00_80_ff_u32; 256 * 256];
1504 let result = encoder.encode(&pixels, 256, 256, false);
1505 assert!(result.is_ok());
1506 let data = result.expect("encode should succeed");
1507 assert!(
1509 data.len() < 256 * 256 * 4,
1510 "compressed size {} should be less than raw size {}",
1511 data.len(),
1512 256 * 256 * 4
1513 );
1514 }
1515
1516 #[test]
1517 fn test_effort_affects_output() {
1518 let pixels = vec![0xff_ff_00_00u32; 64];
1519
1520 let low = Vp8lEncoder::new(0);
1521 let high = Vp8lEncoder::new(50);
1522
1523 let data_low = low.encode(&pixels, 8, 8, false).expect("low effort");
1524 let data_high = high.encode(&pixels, 8, 8, false).expect("high effort");
1525
1526 assert_ne!(data_low, data_high);
1528 }
1529
1530 #[test]
1533 fn test_predictor_transform_uniform() {
1534 let w = 4u32;
1535 let h = 4u32;
1536 let original = vec![0xff_80_40_20u32; (w * h) as usize];
1537 let mut transformed = original.clone();
1538 let result = apply_predictor_transform(&mut transformed, w, h);
1539 assert!(result.is_ok());
1540
1541 for i in 1..(w * h) as usize {
1544 let g = (transformed[i] >> 8) & 0xff;
1545 let r = (transformed[i] >> 16) & 0xff;
1546 let b = transformed[i] & 0xff;
1547 assert_eq!(g, 0, "green residual should be 0 for uniform image");
1548 assert_eq!(r, 0, "red residual should be 0 for uniform image");
1549 assert_eq!(b, 0, "blue residual should be 0 for uniform image");
1550 }
1551 }
1552
1553 #[test]
1554 fn test_predictor_transform_dimension_mismatch() {
1555 let mut pixels = vec![0u32; 10];
1556 let result = apply_predictor_transform(&mut pixels, 4, 4);
1557 assert!(result.is_err());
1558 }
1559
1560 #[test]
1563 fn test_encoder_max_valid_dimension() {
1564 let encoder = Vp8lEncoder::new(0);
1565 let pixels = vec![0xff_00_00_00u32; 1];
1566 let result = encoder.encode(&pixels, 1, 1, false);
1567 assert!(result.is_ok());
1568 }
1569
1570 #[test]
1571 fn test_encoder_effort_clamped() {
1572 let encoder = Vp8lEncoder::new(255);
1574 let pixels = vec![0xff_ff_ff_ffu32; 4];
1575 let result = encoder.encode(&pixels, 2, 2, true);
1576 assert!(result.is_ok());
1577 }
1578}