deflate/compression_options.rs
1//! This module contains the various options to tweak how compression is performed.
2//!
3//! Note that due to the nature of the `DEFLATE` format, lower compression levels
4//! may for some data compress better than higher compression levels.
5//!
6//! For applications where a maximum level of compression (irrespective of compression
7//! speed) is required, consider using the [`Zopfli`](https://crates.io/crates/zopfli)
8//! compressor, which uses a specialised (but slow) algorithm to figure out the maximum
9//! of compression for the provided data.
10//!
11use lz77::MatchingType;
12use std::convert::From;
13
14pub const HIGH_MAX_HASH_CHECKS: u16 = 1768;
15pub const HIGH_LAZY_IF_LESS_THAN: u16 = 128;
16/// The maximum number of hash checks that make sense as this is the length
17/// of the hash chain.
18pub const MAX_HASH_CHECKS: u16 = 32 * 1024;
19pub const DEFAULT_MAX_HASH_CHECKS: u16 = 128;
20pub const DEFAULT_LAZY_IF_LESS_THAN: u16 = 32;
21
22/// An enum describing the level of compression to be used by the encoder
23///
24/// Higher compression ratios will take longer to encode.
25///
26/// This is a simplified interface to specify a compression level.
27///
28/// [See also `CompressionOptions`](./struct.CompressionOptions.html) which provides for
29/// tweaking the settings more finely.
30#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
31pub enum Compression {
32 /// Fast minimal compression (`CompressionOptions::fast()`).
33 Fast,
34 /// Default level (`CompressionOptions::default()`).
35 Default,
36 /// Higher compression level (`CompressionOptions::high()`).
37 ///
38 /// Best in this context isn't actually the highest possible level
39 /// the encoder can do, but is meant to emulate the `Best` setting in the `Flate2`
40 /// library.
41 Best,
42}
43
44impl Default for Compression {
45 fn default() -> Compression {
46 Compression::Default
47 }
48}
49
50/// Enum allowing some special options (not implemented yet)!
51#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
52pub enum SpecialOptions {
53 /// Compress normally.
54 Normal,
55 /// Force fixed huffman tables. (Unimplemented!).
56 _ForceFixed,
57 /// Force stored (uncompressed) blocks only. (Unimplemented!).
58 _ForceStored,
59}
60
61impl Default for SpecialOptions {
62 fn default() -> SpecialOptions {
63 SpecialOptions::Normal
64 }
65}
66
67pub const DEFAULT_OPTIONS: CompressionOptions = CompressionOptions {
68 max_hash_checks: DEFAULT_MAX_HASH_CHECKS,
69 lazy_if_less_than: DEFAULT_LAZY_IF_LESS_THAN,
70 matching_type: MatchingType::Lazy,
71 special: SpecialOptions::Normal,
72};
73
74/// A struct describing the options for a compressor or compression function.
75///
76/// These values are not stable and still subject to change!
77#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
78pub struct CompressionOptions {
79 /// The maximum number of checks to make in the hash table for matches.
80 ///
81 /// Higher numbers mean slower, but better compression. Very high (say `>1024`) values
82 /// will impact compression speed a lot. The maximum match length is 2^15, so values higher than
83 /// this won't make any difference, and will be truncated to 2^15 by the compression
84 /// function/writer.
85 ///
86 /// Default value: `128`
87 pub max_hash_checks: u16,
88 // pub _window_size: u16,
89 /// Only lazy match if we have a length less than this value.
90 ///
91 /// Higher values degrade compression slightly, but improve compression speed.
92 ///
93 /// * `0`: Never lazy match. (Same effect as setting MatchingType to greedy, but may be slower).
94 /// * `1...257`: Only check for a better match if the first match was shorter than this value.
95 /// * `258`: Always lazy match.
96 ///
97 /// As the maximum length of a match is `258`, values higher than this will have
98 /// no further effect.
99 ///
100 /// * Default value: `32`
101 pub lazy_if_less_than: u16,
102
103 // pub _decent_match: u16,
104 /// Whether to use lazy or greedy matching.
105 ///
106 /// Lazy matching will provide better compression, at the expense of compression speed.
107 ///
108 /// As a special case, if max_hash_checks is set to 0, and matching_type is set to lazy,
109 /// compression using only run-length encoding (i.e maximum match distance of 1) is performed.
110 /// (This may be changed in the future but is defined like this at the moment to avoid API
111 /// breakage.
112 ///
113 /// [See `MatchingType`](./enum.MatchingType.html)
114 ///
115 /// * Default value: `MatchingType::Lazy`
116 pub matching_type: MatchingType,
117 /// Force fixed/stored blocks (Not implemented yet).
118 /// * Default value: `SpecialOptions::Normal`
119 pub special: SpecialOptions,
120}
121
122// Some standard profiles for the compression options.
123// Ord should be implemented at some point, but won't yet until the struct is stabilised.
124impl CompressionOptions {
125 /// Returns compression settings rouhgly corresponding to the `HIGH(9)` setting in miniz.
126 pub fn high() -> CompressionOptions {
127 CompressionOptions {
128 max_hash_checks: HIGH_MAX_HASH_CHECKS,
129 lazy_if_less_than: HIGH_LAZY_IF_LESS_THAN,
130 matching_type: MatchingType::Lazy,
131 special: SpecialOptions::Normal,
132 }
133 }
134
135 /// Returns a fast set of compression settings
136 ///
137 /// Ideally this should roughly correspond to the `FAST(1)` setting in miniz.
138 /// However, that setting makes miniz use a somewhat different algorhithm,
139 /// so currently hte fast level in this library is slower and better compressing
140 /// than the corresponding level in miniz.
141 pub fn fast() -> CompressionOptions {
142 CompressionOptions {
143 max_hash_checks: 1,
144 lazy_if_less_than: 0,
145 matching_type: MatchingType::Greedy,
146 special: SpecialOptions::Normal,
147 }
148 }
149
150 /// Returns a set of compression settings that makes the compressor only compress using
151 /// huffman coding. (Ignoring any length/distance matching)
152 ///
153 /// This will normally have the worst compression ratio (besides only using uncompressed data),
154 /// but may be the fastest method in some cases.
155 pub fn huffman_only() -> CompressionOptions {
156 CompressionOptions {
157 max_hash_checks: 0,
158 lazy_if_less_than: 0,
159 matching_type: MatchingType::Greedy,
160 special: SpecialOptions::Normal,
161 }
162 }
163
164 /// Returns a set of compression settings that makes the compressor compress only using
165 /// run-length encoding (i.e only looking for matches one byte back).
166 ///
167 /// This is very fast, but tends to compress worse than looking for more matches using hash
168 /// chains that the slower settings do.
169 /// Works best on data that has runs of equivialent bytes, like binary or simple images,
170 /// less good for text.
171 pub fn rle() -> CompressionOptions {
172 CompressionOptions {
173 max_hash_checks: 0,
174 lazy_if_less_than: 0,
175 matching_type: MatchingType::Lazy,
176 special: SpecialOptions::Normal,
177 }
178 }
179}
180
181impl Default for CompressionOptions {
182 /// Returns the options describing the default compression level.
183 fn default() -> CompressionOptions {
184 DEFAULT_OPTIONS
185 }
186}
187
188impl From<Compression> for CompressionOptions {
189 fn from(compression: Compression) -> CompressionOptions {
190 match compression {
191 Compression::Fast => CompressionOptions::fast(),
192 Compression::Default => CompressionOptions::default(),
193 Compression::Best => CompressionOptions::high(),
194 }
195 }
196}