ptouch/
tiff.rs

1//! TIFF compression functions
2// Rust PTouch Driver / Utility
3//
4// https://github.com/ryankurte/rust-ptouch
5// Copyright 2021 Ryan Kurte
6
7#[derive(Clone, Debug, PartialEq)]
8enum CompressMode {
9    None(u8),
10    Repeated(u8, usize),
11    Unique(Vec<u8>),
12}
13
14// TODO: incomplete implementation, does not consider > 16 case from docs
15pub fn compress(data: &[u8]) -> Vec<u8> {
16    let mut c = Vec::<u8>::new();
17
18    let mut state = CompressMode::None(data[0]);
19
20    // Perform byte-wise compression
21    for i in 1..data.len() {
22        state = match state {
23            CompressMode::None(v) if data[i] == v => CompressMode::Repeated(v, 1),
24            CompressMode::None(v) => CompressMode::Unique(vec![v, data[i]]),
25            CompressMode::Repeated(v, n) if data[i] == v => CompressMode::Repeated(v, n + 1),
26            CompressMode::Repeated(v, n) => {
27                let count = 0xFF - (n as u8 - 1);
28
29                c.push(count as u8);
30                c.push(v);
31
32                CompressMode::None(data[i])
33            }
34            CompressMode::Unique(mut v) if data[i] != v[v.len() - 1] => {
35                v.push(data[i]);
36
37                CompressMode::Unique(v)
38            }
39            CompressMode::Unique(v) => {
40                let count = v.len() - 1;
41
42                c.push(count as u8);
43                c.extend_from_slice(&v[..count]);
44
45                CompressMode::Repeated(data[i], 2)
46            }
47        };
48    }
49
50    // Finalize any pending data
51    match state {
52        CompressMode::None(v) => {
53            c.push(0x00);
54            c.push(v);
55        }
56        CompressMode::Repeated(v, n) => {
57            let count = 0xFF - (n as u8 - 1);
58
59            c.push(count as u8);
60            c.push(v);
61        }
62        CompressMode::Unique(v) => {
63            let count = v.len() - 1;
64
65            c.push(count as u8);
66            c.extend_from_slice(&v);
67        }
68    }
69
70    // If the encoded length > 16, just use this in simple mode.
71    if c.len() > 16 {
72        c = vec![];
73        c.push(data.len() as u8);
74        c.extend_from_slice(data);
75    }
76
77    c
78}
79
80pub fn uncompress(data: &[u8]) -> Vec<u8> {
81    let mut u = vec![];
82    let mut i: usize = 0;
83
84    loop {
85        let d = data[i] as i8;
86
87        if d < 0 {
88            // -ve indicates repeated chars
89            let mut r = vec![data[i+1]; (-d+1) as usize];
90            u.append(&mut r);
91            i += 2;
92        } else {
93            // +ve indicates literal sequence
94            let c = d as usize;
95            u.extend_from_slice(&data[i+1..i+c+2]);
96            i += c + 2;
97        }
98
99        if i >= data.len() {
100            break;
101        }
102    }
103
104    return u
105}
106
107#[cfg(test)]
108mod test {
109    #[test]
110    fn test_raster_compression() {
111        let uncompressed = [
112            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x23, 0xBA, 0xBF, 0xA2, 0x22, 0x2B,
114        ];
115        let compressed = [
116            0xED, 0x00, 0xFF, 0x22, 0x05, 0x23, 0xBA, 0xBF, 0xA2, 0x22, 0x2B,
117        ];
118
119        let c = super::compress(&uncompressed);
120
121        assert_eq!(
122            c, compressed,
123            "Compressed: {:02x?} Expected: {:02x?}",
124            &c, &compressed
125        );
126
127        let d = super::uncompress(&compressed);
128
129        assert_eq!(
130            d, uncompressed,
131            "Uncompressed: {:02x?} Expected: {:02x?}",
132            &d, &uncompressed
133        );
134    }
135
136    // TODO: test compress / decompress as something is definitely not -right-
137}