/rust/registry/src/index.crates.io-6f17d22bba15001f/fdeflate-0.3.7/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
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 | 0 | pub fn compute_code_lengths( |
40 | 0 | freqs: &[u64], |
41 | 0 | min_limit: &[u8], |
42 | 0 | max_limit: &[u8], |
43 | 0 | calculated_nbits: &mut [u8], |
44 | 0 | ) { |
45 | 0 | debug_assert_eq!(freqs.len(), min_limit.len()); |
46 | 0 | debug_assert_eq!(freqs.len(), max_limit.len()); |
47 | 0 | debug_assert_eq!(freqs.len(), calculated_nbits.len()); |
48 | 0 | let len = freqs.len(); |
49 | | |
50 | 0 | for i in 0..len { |
51 | 0 | debug_assert!(min_limit[i] >= 1); |
52 | 0 | debug_assert!(min_limit[i] <= max_limit[i]); |
53 | | } |
54 | | |
55 | 0 | let precision = *max_limit.iter().max().unwrap(); |
56 | 0 | let num_patterns = 1 << precision; |
57 | 0 |
|
58 | 0 | let mut dynp = vec![u64::MAX; (num_patterns + 1) * (len + 1)]; |
59 | 0 | let index = |sym: usize, off: usize| sym * (num_patterns + 1) + off; |
60 | | |
61 | 0 | dynp[index(0, 0)] = 0; |
62 | 0 | for sym in 0..len { |
63 | 0 | for bits in min_limit[sym]..=max_limit[sym] { |
64 | 0 | let off_delta = 1 << (precision - bits); |
65 | 0 | for off in 0..=num_patterns.saturating_sub(off_delta) { |
66 | 0 | dynp[index(sym + 1, off + off_delta)] = dynp[index(sym, off)] |
67 | 0 | .saturating_add(freqs[sym] * u64::from(bits)) |
68 | 0 | .min(dynp[index(sym + 1, off + off_delta)]); |
69 | 0 | } |
70 | | } |
71 | | } |
72 | | |
73 | 0 | let mut sym = len; |
74 | 0 | let mut off = num_patterns; |
75 | | |
76 | 0 | while sym > 0 { |
77 | 0 | sym -= 1; |
78 | 0 | assert!(off > 0); |
79 | | |
80 | 0 | for bits in min_limit[sym]..=max_limit[sym] { |
81 | 0 | let off_delta = 1 << (precision - bits); |
82 | 0 | if off_delta <= off |
83 | 0 | && dynp[index(sym + 1, off)] |
84 | 0 | == dynp[index(sym, off - off_delta)] |
85 | 0 | .saturating_add(freqs[sym] * u64::from(bits)) |
86 | | { |
87 | 0 | off -= off_delta; |
88 | 0 | calculated_nbits[sym] = bits; |
89 | 0 | break; |
90 | 0 | } |
91 | | } |
92 | | } |
93 | | |
94 | 0 | for i in 0..len { |
95 | 0 | debug_assert!(calculated_nbits[i] >= min_limit[i]); |
96 | 0 | debug_assert!(calculated_nbits[i] <= max_limit[i]); |
97 | | } |
98 | 0 | } |
99 | | |
100 | 0 | const fn compute_codes<const NSYMS: usize>(lengths: &[u8; NSYMS]) -> Option<[u16; NSYMS]> { |
101 | 0 | let mut codes = [0u16; NSYMS]; |
102 | 0 |
|
103 | 0 | let mut code = 0u32; |
104 | 0 |
|
105 | 0 | let mut len = 1; |
106 | 0 | while len <= 16 { |
107 | 0 | let mut i = 0; |
108 | 0 | while i < lengths.len() { |
109 | 0 | if lengths[i] == len { |
110 | 0 | codes[i] = (code as u16).reverse_bits() >> (16 - len); |
111 | 0 | code += 1; |
112 | 0 | } |
113 | 0 | i += 1; |
114 | | } |
115 | 0 | code <<= 1; |
116 | 0 | len += 1; |
117 | | } |
118 | | |
119 | 0 | if code == 2 << 16 { |
120 | 0 | Some(codes) |
121 | | } else { |
122 | 0 | None |
123 | | } |
124 | 0 | } |