1 | //! A fast deflate implementation. |
2 | //! |
3 | //! This crate contains an optimized implementation of the deflate algorithm tuned to compress PNG |
4 | //! images. It is compatible with standard zlib, but make a bunch of simplifying assumptions that |
5 | //! drastically improve encoding performance: |
6 | //! |
7 | //! - Exactly one block per deflate stream. |
8 | //! - No distance codes except for run length encoding of zeros. |
9 | //! - A single fixed huffman tree trained on a large corpus of PNG images. |
10 | //! - All huffman codes are 12 bits or less. |
11 | //! |
12 | //! It also contains a fast decompressor that supports arbitrary zlib streams but does especially |
13 | //! well on streams that meet the above assumptions. |
14 | //! |
15 | //! # Inspiration |
16 | //! |
17 | //! The algorithms in this crate take inspiration from multiple sources: |
18 | //! * [fpnge](https://github.com/veluca93/fpnge) |
19 | //! * [zune-inflate](https://github.com/etemesi254/zune-image/tree/main/zune-inflate) |
20 | //! * [RealTime Data Compression blog](https://fastcompression.blogspot.com/2015/10/huffman-revisited-part-4-multi-bytes.html) |
21 | #![forbid (unsafe_code)] |
22 | #![warn (missing_docs)] |
23 | |
24 | mod compress; |
25 | mod decompress; |
26 | mod huffman; |
27 | mod tables; |
28 | |
29 | pub use compress::{compress_to_vec, Compressor, StoredOnlyCompressor}; |
30 | pub use decompress::{ |
31 | decompress_to_vec, decompress_to_vec_bounded, BoundedDecompressionError, DecompressionError, |
32 | Decompressor, |
33 | }; |
34 | |
35 | /// Build a length limited huffman tree. |
36 | /// |
37 | /// Dynamic programming algorithm from fpnge. |
38 | #[doc (hidden)] |
39 | pub fn compute_code_lengths( |
40 | freqs: &[u64], |
41 | min_limit: &[u8], |
42 | max_limit: &[u8], |
43 | calculated_nbits: &mut [u8], |
44 | ) { |
45 | debug_assert_eq!(freqs.len(), min_limit.len()); |
46 | debug_assert_eq!(freqs.len(), max_limit.len()); |
47 | debug_assert_eq!(freqs.len(), calculated_nbits.len()); |
48 | let len = freqs.len(); |
49 | |
50 | for i in 0..len { |
51 | debug_assert!(min_limit[i] >= 1); |
52 | debug_assert!(min_limit[i] <= max_limit[i]); |
53 | } |
54 | |
55 | let precision = *max_limit.iter().max().unwrap(); |
56 | let num_patterns = 1 << precision; |
57 | |
58 | let mut dynp = vec![u64::MAX; (num_patterns + 1) * (len + 1)]; |
59 | let index = |sym: usize, off: usize| sym * (num_patterns + 1) + off; |
60 | |
61 | dynp[index(0, 0)] = 0; |
62 | for sym in 0..len { |
63 | for bits in min_limit[sym]..=max_limit[sym] { |
64 | let off_delta = 1 << (precision - bits); |
65 | for off in 0..=num_patterns.saturating_sub(off_delta) { |
66 | dynp[index(sym + 1, off + off_delta)] = dynp[index(sym, off)] |
67 | .saturating_add(freqs[sym] * u64::from(bits)) |
68 | .min(dynp[index(sym + 1, off + off_delta)]); |
69 | } |
70 | } |
71 | } |
72 | |
73 | let mut sym = len; |
74 | let mut off = num_patterns; |
75 | |
76 | while sym > 0 { |
77 | sym -= 1; |
78 | assert!(off > 0); |
79 | |
80 | for bits in min_limit[sym]..=max_limit[sym] { |
81 | let off_delta = 1 << (precision - bits); |
82 | if off_delta <= off |
83 | && dynp[index(sym + 1, off)] |
84 | == dynp[index(sym, off - off_delta)] |
85 | .saturating_add(freqs[sym] * u64::from(bits)) |
86 | { |
87 | off -= off_delta; |
88 | calculated_nbits[sym] = bits; |
89 | break; |
90 | } |
91 | } |
92 | } |
93 | |
94 | for i in 0..len { |
95 | debug_assert!(calculated_nbits[i] >= min_limit[i]); |
96 | debug_assert!(calculated_nbits[i] <= max_limit[i]); |
97 | } |
98 | } |
99 | |
100 | const fn compute_codes<const NSYMS: usize>(lengths: &[u8; NSYMS]) -> Option<[u16; NSYMS]> { |
101 | let mut codes = [0u16; NSYMS]; |
102 | |
103 | let mut code = 0u32; |
104 | |
105 | let mut len = 1; |
106 | while len <= 16 { |
107 | let mut i = 0; |
108 | while i < lengths.len() { |
109 | if lengths[i] == len { |
110 | codes[i] = (code as u16).reverse_bits() >> (16 - len); |
111 | code += 1; |
112 | } |
113 | i += 1; |
114 | } |
115 | code <<= 1; |
116 | len += 1; |
117 | } |
118 | |
119 | if code == 2 << 16 { |
120 | Some(codes) |
121 | } else { |
122 | None |
123 | } |
124 | } |
125 | |