pixie_anim_lib/lzw/
mod.rs1use crate::bits::BitWriter;
6use crate::error::Result;
7
8const MAX_CODES: u16 = 4096;
9
10pub struct LzwEncoder {
12 min_code_size: u8,
13 dictionary: Vec<i32>,
14 pub lossiness: u8,
16}
17
18impl LzwEncoder {
19 pub fn new(min_code_size: u8) -> Self {
21 Self {
22 min_code_size,
23 dictionary: vec![-1i32; MAX_CODES as usize * 256],
24 lossiness: 0,
25 }
26 }
27
28 pub fn encode(&mut self, data: &[u8], buffer: &mut Vec<u8>) -> Result<()> {
30 let clear_code = 1 << self.min_code_size;
31 let eoi_code = clear_code + 1;
32
33 let mut bit_writer = BitWriter::new(buffer);
34 let mut code_size = self.min_code_size + 1;
35 let mut next_code = eoi_code + 1;
36
37 self.dictionary.fill(-1);
38
39 bit_writer.write_bits(clear_code, code_size);
40
41 if data.is_empty() {
42 bit_writer.write_bits(eoi_code, code_size);
43 bit_writer.flush();
44 return Ok(());
45 }
46
47 let mut prefix = data[0] as u16;
48
49 for &byte in &data[1..] {
50 let character = byte;
51 let dict_idx = ((prefix as usize) << 8) | character as usize;
52 let code = self.dictionary[dict_idx];
53
54 if code != -1 {
55 prefix = code as u16;
56 } else {
57 let mut found_lossy = false;
62 if self.lossiness > 0 {
63 for offset in 1..=(self.lossiness as i16) {
65 for sign in &[-1, 1] {
66 let neighbor = character as i16 + (offset * sign);
67 if (0..=255).contains(&neighbor) {
68 let n_idx = ((prefix as usize) << 8) | neighbor as usize;
69 let n_code = self.dictionary[n_idx];
70 if n_code != -1 {
71 prefix = n_code as u16;
72 found_lossy = true;
73 break;
74 }
75 }
76 }
77 if found_lossy {
78 break;
79 }
80 }
81 }
82
83 if !found_lossy {
84 bit_writer.write_bits(prefix, code_size);
85
86 if next_code < MAX_CODES {
87 self.dictionary[dict_idx] = next_code as i32;
88 next_code += 1;
89
90 if next_code > (1 << code_size) && code_size < 12 {
91 code_size += 1;
92 }
93 } else {
94 bit_writer.write_bits(clear_code, code_size);
95 self.dictionary.fill(-1);
96 code_size = self.min_code_size + 1;
97 next_code = eoi_code + 1;
98 }
99
100 prefix = character as u16;
101 }
102 }
103 }
104
105 bit_writer.write_bits(prefix, code_size);
106 bit_writer.write_bits(eoi_code, code_size);
107 bit_writer.flush();
108
109 Ok(())
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_basic_lzw() {
119 let mut encoder = LzwEncoder::new(8);
120 let data = vec![1, 1, 1, 1, 1];
121 let mut out = Vec::new();
122 encoder.encode(&data, &mut out).unwrap();
123 assert!(!out.is_empty());
124 }
125}