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}