From fe9cd01b828b0bd35c7d51758a00313f5c46593d Mon Sep 17 00:00:00 2001 From: Josh Holmer Date: Tue, 30 Jan 2018 23:52:37 -0500 Subject: [PATCH] Replace miniz_sys with miniz_oxide, a Rust implementation of miniz This also improves decompression performance by 15%, and obsoletes the `--zm` parameter. Closes #57 --- CHANGELOG.md | 6 +- Cargo.lock | 16 ++-- Cargo.toml | 2 +- benches/deflate.rs | 42 ++++----- src/deflate/miniz_stream.rs | 165 ++++++++++-------------------------- src/deflate/mod.rs | 41 ++------- src/lib.rs | 53 ++++-------- src/main.rs | 34 ++------ src/png/mod.rs | 5 +- 9 files changed, 104 insertions(+), 260 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bc90791..b87d55fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,11 @@ -### Version 0.19.1 (unreleased) +### Version 0.20.0 (unreleased) - Refactor of internal code. - Implement unix-specific permissions copying for `-p` option - Performance optimizations + - Remove the C dependency on miniz, and replace it with a Rust version ([#57](https://github.com/shssoichiro/oxipng/issues/57)) + - This improves decompression speed by 15%. Compression speed is not affected. + - [SEMVER_MAJOR] This also obsoletes the `-zm` command line option and the `memory` key on the `Options` struct. + - Presets will be updated automatically. This means that presets 3 and higher will run significantly more quickly. ### Version 0.19.0 - [SEMVER_MAJOR] Default to overwriting the input file if `out_file` is not set. diff --git a/Cargo.lock b/Cargo.lock index 1db52cf9..612c1546 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,11 +71,6 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cc" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "clap" version = "2.29.2" @@ -274,11 +269,11 @@ dependencies = [ ] [[package]] -name = "miniz-sys" -version = "0.1.10" +name = "miniz_oxide" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -334,7 +329,7 @@ dependencies = [ "image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -657,7 +652,6 @@ dependencies = [ "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" -"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0" "checksum clap 2.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4151c5790817c7d21bbdc6c3530811f798172915f93258244948b93ba19604a6" "checksum clippy 0.0.184 (registry+https://github.com/rust-lang/crates.io-index)" = "1e70c0ea9c5ad3eaab76ec3c4351d8d415c257093173416b0e2ed75e9be5cb74" "checksum clippy_lints 0.0.184 (registry+https://github.com/rust-lang/crates.io-index)" = "b86054e0d81947d1db08e5931521dbea49619079c5fad91583d710c854a0e994" @@ -683,7 +677,7 @@ dependencies = [ "checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" -"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" +"checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-rational 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "0b950f75e042fdd710460084d19c8efdcd72d65183ead8ecd04b90483f5a55d2" diff --git a/Cargo.toml b/Cargo.toml index dabf86d0..698b9b4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,10 +28,10 @@ crc = "^1.2.0" glob = "0.2.11" itertools = "^0.7.0" libc = "^0.2.4" -miniz-sys = "^0.1.7" num_cpus = "^1.0.0" rayon = "^0.9.0" zopfli = "^0.3.4" +miniz_oxide = "0.1.2" [dependencies.clap] optional = true diff --git a/benches/deflate.rs b/benches/deflate.rs index c36254f0..c829190f 100644 --- a/benches/deflate.rs +++ b/benches/deflate.rs @@ -14,7 +14,7 @@ fn deflate_16_bits_strategy_0(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 0, 15); }); } @@ -24,7 +24,7 @@ fn deflate_8_bits_strategy_0(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 0, 15); }); } @@ -36,7 +36,7 @@ fn deflate_4_bits_strategy_0(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 0, 15); }); } @@ -48,7 +48,7 @@ fn deflate_2_bits_strategy_0(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 0, 15); }); } @@ -60,7 +60,7 @@ fn deflate_1_bits_strategy_0(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 0, 15); }); } @@ -70,7 +70,7 @@ fn deflate_16_bits_strategy_1(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 1, 15); }); } @@ -80,7 +80,7 @@ fn deflate_8_bits_strategy_1(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 1, 15); }); } @@ -92,7 +92,7 @@ fn deflate_4_bits_strategy_1(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 1, 15); }); } @@ -104,7 +104,7 @@ fn deflate_2_bits_strategy_1(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 1, 15); }); } @@ -116,7 +116,7 @@ fn deflate_1_bits_strategy_1(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 1, 15); }); } @@ -126,7 +126,7 @@ fn deflate_16_bits_strategy_2(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 2, 15); }); } @@ -136,7 +136,7 @@ fn deflate_8_bits_strategy_2(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 2, 15); }); } @@ -148,7 +148,7 @@ fn deflate_4_bits_strategy_2(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 2, 15); }); } @@ -160,7 +160,7 @@ fn deflate_2_bits_strategy_2(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 2, 15); }); } @@ -172,7 +172,7 @@ fn deflate_1_bits_strategy_2(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 2, 15); }); } @@ -182,7 +182,7 @@ fn deflate_16_bits_strategy_3(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 3, 15); }); } @@ -192,7 +192,7 @@ fn deflate_8_bits_strategy_3(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 3, 15); }); } @@ -204,7 +204,7 @@ fn deflate_4_bits_strategy_3(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 3, 15); }); } @@ -216,7 +216,7 @@ fn deflate_2_bits_strategy_3(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 3, 15); }); } @@ -228,7 +228,7 @@ fn deflate_1_bits_strategy_3(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + deflate::deflate(png.raw_data.as_ref(), 9, 3, 15); }); } @@ -238,6 +238,6 @@ fn inflate_generic(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - deflate::inflate(png.idat_data.as_ref()).ok(); + deflate::inflate(png.idat_data.as_ref()); }); } diff --git a/src/deflate/miniz_stream.rs b/src/deflate/miniz_stream.rs index 1a6987f8..f9b44536 100644 --- a/src/deflate/miniz_stream.rs +++ b/src/deflate/miniz_stream.rs @@ -1,131 +1,52 @@ -// Raw un-exported bindings to miniz for encoding/decoding -// Copyright (c) 2014 Alex Crichton, MIT & Apache licenses -// Originally from flate2 crate -// Modified for use in oxipng +use miniz_oxide::deflate::core::*; -use std::marker; -use std::mem; -use libc::{c_int, c_uint}; -use miniz_sys; +pub fn compress_to_vec_oxipng(input: &[u8], level: u8, window_bits: i32, strategy: i32) -> Vec { + // The comp flags function sets the zlib flag if the window_bits parameter is > 0. + let flags = create_comp_flags_from_zip_params(level.into(), window_bits, strategy); + let mut compressor = CompressorOxide::new(flags); + let mut output = Vec::with_capacity(input.len() / 2); + // # Unsafe + // We trust compress to not read the uninitialized bytes. + unsafe { + let cap = output.capacity(); + output.set_len(cap); + } + let mut in_pos = 0; + let mut out_pos = 0; + loop { + let (status, bytes_in, bytes_out) = compress( + &mut compressor, + &input[in_pos..], + &mut output[out_pos..], + TDEFLFlush::Finish, + ); -pub struct Stream { - raw: miniz_sys::mz_stream, - _marker: marker::PhantomData, -} + out_pos += bytes_out; + in_pos += bytes_in; -pub enum Compress {} -pub enum Decompress {} - -#[doc(hidden)] -pub trait Direction { - unsafe fn destroy(stream: *mut miniz_sys::mz_stream) -> c_int; -} - -impl Stream { - pub fn new_compress( - lvl: c_int, - window_bits: c_int, - mem_size: c_int, - strategy: c_int, - ) -> Stream { - unsafe { - let mut state: miniz_sys::mz_stream = mem::zeroed(); - let ret = miniz_sys::mz_deflateInit2( - &mut state, - lvl, - miniz_sys::MZ_DEFLATED, - window_bits, - mem_size, - strategy, - ); - debug_assert_eq!(ret, 0); - Stream { - raw: state, - _marker: marker::PhantomData, + match status { + TDEFLStatus::Done => { + output.truncate(out_pos); + break; } - } - } + TDEFLStatus::Okay => { + // We need more space, so extend the vector. + if output.len().saturating_sub(out_pos) < 30 { + let current_len = output.len(); + output.reserve(current_len); - pub fn new_decompress() -> Stream { - unsafe { - let mut state: miniz_sys::mz_stream = mem::zeroed(); - let ret = miniz_sys::mz_inflateInit2(&mut state, 15); - debug_assert_eq!(ret, 0); - Stream { - raw: state, - _marker: marker::PhantomData, + // # Unsafe + // We trust compress to not read the uninitialized bytes. + unsafe { + let cap = output.capacity(); + output.set_len(cap); + } + } } + // Not supposed to happen unless there is a bug. + _ => panic!("Bug! Unexpectedly failed to compress!"), } } -} - -impl Stream { - #[inline] - pub fn total_in(&self) -> usize { - self.raw.total_in as usize - } - - #[inline] - pub fn total_out(&self) -> usize { - self.raw.total_out as usize - } -} - -impl Stream { - pub fn decompress_vec(&mut self, input: &mut [u8], output: &mut Vec) -> c_int { - self.raw.avail_in = (input.len() - self.total_in()) as c_uint; - self.raw.avail_out = (output.capacity() - self.total_out()) as c_uint; - - unsafe { - self.raw.next_in = input.as_mut_ptr().offset(self.total_in() as isize); - self.raw.next_out = output.as_mut_ptr().offset(self.total_out() as isize); - let rc = miniz_sys::mz_inflate(&mut self.raw, miniz_sys::MZ_NO_FLUSH); - output.set_len(self.total_out() as usize); - rc - } - } -} - -impl Stream { - pub fn compress_vec(&mut self, input: &mut [u8], output: &mut Vec) -> c_int { - self.raw.avail_in = (input.len() - self.total_in() as usize) as c_uint; - self.raw.avail_out = (output.capacity() - self.total_out() as usize) as c_uint; - - unsafe { - self.raw.next_in = input.as_mut_ptr().offset(self.total_in() as isize); - self.raw.next_out = output.as_mut_ptr().offset(self.total_out() as isize); - let rc = miniz_sys::mz_deflate( - &mut self.raw, - if self.raw.avail_in > 0 { - miniz_sys::MZ_NO_FLUSH - } else { - miniz_sys::MZ_FINISH - }, - ); - output.set_len(self.total_out() as usize); - rc - } - } -} - -impl Direction for Compress { - #[inline] - unsafe fn destroy(stream: *mut miniz_sys::mz_stream) -> c_int { - miniz_sys::mz_deflateEnd(stream) - } -} -impl Direction for Decompress { - #[inline] - unsafe fn destroy(stream: *mut miniz_sys::mz_stream) -> c_int { - miniz_sys::mz_inflateEnd(stream) - } -} - -impl Drop for Stream { - #[inline] - fn drop(&mut self) { - unsafe { - let _ = ::destroy(&mut self.raw); - } - } + + output } diff --git a/src/deflate/mod.rs b/src/deflate/mod.rs index bde23e9b..b42c9a17 100644 --- a/src/deflate/mod.rs +++ b/src/deflate/mod.rs @@ -1,5 +1,5 @@ use error::PngError; -use miniz_sys; +use miniz_oxide; use std::cmp::max; use zopfli; @@ -8,44 +8,13 @@ pub mod miniz_stream; /// Decompress a data stream using the DEFLATE algorithm pub fn inflate(data: &[u8]) -> Result, PngError> { - let mut input = data.to_owned(); - let mut stream = miniz_stream::Stream::new_decompress(); - let mut output = Vec::with_capacity(data.len()); - loop { - match stream.decompress_vec(input.as_mut(), output.as_mut()) { - miniz_sys::MZ_OK => output.reserve(data.len()), - miniz_sys::MZ_STREAM_END => break, - c => return Err(PngError::new(&format!("Error code on decompress: {}", c))), - } - } - output.shrink_to_fit(); - - Ok(output) + miniz_oxide::inflate::decompress_to_vec_zlib(data) + .map_err(|e| PngError::new(&format!("Error on decompress: {:?}", e))) } /// Compress a data stream using the DEFLATE algorithm -pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result, PngError> { - let mut input = data.to_owned(); - // Compressed input should be smaller than decompressed, so allocate less than data.len() - // However, it needs a minimum capacity in order to handle very small images - let mut output = Vec::with_capacity(max(1024, data.len() / 20)); - let mut stream = miniz_stream::Stream::new_compress( - i32::from(zc), - i32::from(zw), - i32::from(zm), - i32::from(zs), - ); - loop { - match stream.compress_vec(input.as_mut(), output.as_mut()) { - miniz_sys::MZ_OK => output.reserve(max(1024, data.len() / 20)), - miniz_sys::MZ_STREAM_END => break, - c => return Err(PngError::new(&format!("Error code on compress: {}", c))), - } - } - - output.shrink_to_fit(); - - Ok(output) +pub fn deflate(data: &[u8], zc: u8, zs: u8, zw: u8) -> Vec { + miniz_stream::compress_to_vec_oxipng(data, zc, zw.into(), zs.into()) } pub fn zopfli_deflate(data: &[u8]) -> Result, PngError> { diff --git a/src/lib.rs b/src/lib.rs index e79e143b..51119001 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ extern crate crc; extern crate image; extern crate itertools; extern crate libc; -extern crate miniz_sys; +extern crate miniz_oxide; extern crate num_cpus; extern crate rayon; extern crate zopfli; @@ -103,10 +103,6 @@ pub struct Options { /// /// Default: `9` pub compression: HashSet, - /// Which zlib memory levels to try on the file (1-9) - /// - /// Default: `9` - pub memory: HashSet, /// Which zlib compression strategies to try on the file (0-3) /// /// Default: `0-3` @@ -193,9 +189,8 @@ impl Options { self } - fn apply_preset_3(mut self) -> Self { - self.memory.insert(8); - self + fn apply_preset_3(self) -> Self { + self.apply_preset_2() } fn apply_preset_4(mut self) -> Self { @@ -216,7 +211,6 @@ impl Options { for i in 1..3 { self.compression.insert(i); } - self.memory.insert(7); self.apply_preset_5() } } @@ -229,8 +223,6 @@ impl Default for Options { filter.insert(5); let mut compression = HashSet::new(); compression.insert(9); - let mut memory = HashSet::new(); - memory.insert(9); let mut strategies = HashSet::new(); for i in 0..4 { strategies.insert(i); @@ -259,7 +251,6 @@ impl Default for Options { filter, interlace: None, compression, - memory, strategies, window: 15, alphas, @@ -381,7 +372,6 @@ pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result, PngE struct TrialOptions { pub filter: u8, pub compression: u8, - pub memory: u8, pub strategy: u8, } @@ -423,7 +413,6 @@ fn optimize_png( let mut filter = opts.filter.iter().cloned().collect::>(); let compression = &opts.compression; - let memory = &opts.memory; let mut strategies = opts.strategies.clone(); if opts.use_heuristics { @@ -452,7 +441,7 @@ fn optimize_png( if opts.idat_recoding || reduction_occurred { // Go through selected permutations and determine the best let combinations = if opts.deflate == Deflaters::Zlib { - filter.len() * compression.len() * memory.len() * strategies.len() + filter.len() * compression.len() * strategies.len() } else { filter.len() }; @@ -464,15 +453,12 @@ fn optimize_png( for f in &filter { if opts.deflate == Deflaters::Zlib { for zc in compression { - for zm in memory { - for zs in &strategies { - results.push(TrialOptions { - filter: *f, - compression: *zc, - memory: *zm, - strategy: *zs, - }); - } + for zs in &strategies { + results.push(TrialOptions { + filter: *f, + compression: *zc, + strategy: *zs, + }); } } } else { @@ -480,7 +466,6 @@ fn optimize_png( results.push(TrialOptions { filter: *f, compression: 0, - memory: 0, strategy: 0, }); } @@ -504,22 +489,15 @@ fn optimize_png( .filter_map(|trial| { let filtered = &filters[&trial.filter]; let new_idat = if opts.deflate == Deflaters::Zlib { - deflate::deflate( - filtered, - trial.compression, - trial.memory, - trial.strategy, - opts.window, - ) + deflate::deflate(filtered, trial.compression, trial.strategy, opts.window) } else { - deflate::zopfli_deflate(filtered) - }.unwrap(); + deflate::zopfli_deflate(filtered).unwrap() + }; if opts.verbosity == Some(1) { eprintln!( - " zc = {} zm = {} zs = {} f = {} {} bytes", + " zc = {} zs = {} f = {} {} bytes", trial.compression, - trial.memory, trial.strategy, trial.filter, new_idat.len() @@ -540,9 +518,8 @@ fn optimize_png( let opts = better.0; eprintln!("Found better combination:"); eprintln!( - " zc = {} zm = {} zs = {} f = {} {} bytes", + " zc = {} zs = {} f = {} {} bytes", opts.compression, - opts.memory, opts.strategy, opts.filter, png.idat_data.len() diff --git a/src/main.rs b/src/main.rs index 399010b1..95c8840a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -128,16 +128,6 @@ fn main() { Err(_) => Err("Invalid option for compression".to_owned()), } })) - .arg(Arg::with_name("memory") - .help("zlib memory levels (1-9) - Default: 9") - .long("zm") - .takes_value(true) - .validator(|x| { - match parse_numeric_range_opts(&x, 1, 9) { - Ok(_) => Ok(()), - Err(_) => Err("Invalid option for memory".to_owned()), - } - })) .arg(Arg::with_name("strategies") .help("zlib compression strategies (0-3) - Default: 0-3") .long("zs") @@ -210,19 +200,15 @@ fn main() { } })) .after_help("Optimization levels: - -o 0 => --zc 3 --nz (0 or 1 trials) - -o 1 => --zc 9 (1 trial, determined heuristically) - -o 2 => --zc 9 --zs 0-3 -f 0,5 (8 trials) - -o 3 => --zc 9 --zm 8-9 --zs 0-3 -f 0,5 (16 trials) - -o 4 => --zc 9 --zm 8-9 --zs 0-3 -f 0-5 (48 trials) - -o 5 => --zc 3-9 --zm 8-9 --zs 0-3 -f 0-5 (192 trials) - -o 6 => --zc 1-9 --zm 7-9 --zs 0-3 -f 0-5 (360 trials) - -o 6 --zm 1-9 => --zc 1-9 --zm 1-9 --zs 0-3 -f 0-5 (1080 trials) + -o 0 => --zc 3 --nz (0 or 1 trials) + -o 1 => --zc 9 (1 trial, determined heuristically) + -o 2 => --zc 9 --zs 0-3 -f 0,5 (8 trials) + -o 3 => --zc 9 --zs 0-3 -f 0,5 (8 trials, currently identical to preset 3) + -o 4 => --zc 9 --zs 0-3 -f 0-5 (24 trials) + -o 5 => --zc 3-9 --zs 0-3 -f 0-5 (96 trials) + -o 6 => --zc 1-9 --zs 0-3 -f 0-5 (180 trials) - Exhaustive combinations such as \"-o 6 --zm 1-9\" are not generally recommended. - These are very slow and generally provide no compression gain. - - Manually specifying a compression option (zc, zm, etc.) will override the optimization preset, + Manually specifying a compression option (zc, zs, etc.) will override the optimization preset, regardless of the order you write the arguments.") .get_matches(); @@ -303,10 +289,6 @@ fn parse_opts_into_struct(matches: &ArgMatches) -> Result { opts.compression = parse_numeric_range_opts(x, 1, 9).unwrap(); } - if let Some(x) = matches.value_of("memory") { - opts.memory = parse_numeric_range_opts(x, 1, 9).unwrap(); - } - if let Some(x) = matches.value_of("strategies") { opts.strategies = parse_numeric_range_opts(x, 0, 3).unwrap(); } diff --git a/src/png/mod.rs b/src/png/mod.rs index afa163d7..6736c786 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -17,7 +17,6 @@ use std::iter::Iterator; use std::path::Path; const STD_COMPRESSION: u8 = 8; -const STD_MEMORY: u8 = 9; const STD_STRATEGY: u8 = 2; // Huffman only const STD_WINDOW: u8 = 15; const STD_FILTERS: [u8; 2] = [0, 5]; @@ -616,11 +615,9 @@ impl PngData { deflate::deflate( &image.filter_image(*f), STD_COMPRESSION, - STD_MEMORY, STD_STRATEGY, STD_WINDOW, - ).unwrap() - .len() + ).len() }) .min() .unwrap();