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
This commit is contained in:
Josh Holmer 2018-01-30 23:52:37 -05:00
parent 0c2e3777b1
commit fe9cd01b82
9 changed files with 104 additions and 260 deletions

View file

@ -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.

16
Cargo.lock generated
View file

@ -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"

View file

@ -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

View file

@ -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());
});
}

View file

@ -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<u8> {
// 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<D: Direction> {
raw: miniz_sys::mz_stream,
_marker: marker::PhantomData<D>,
}
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<Compress> {
pub fn new_compress(
lvl: c_int,
window_bits: c_int,
mem_size: c_int,
strategy: c_int,
) -> Stream<Compress> {
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<Decompress> {
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<T: Direction> Stream<T> {
#[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<Decompress> {
pub fn decompress_vec(&mut self, input: &mut [u8], output: &mut Vec<u8>) -> 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<Compress> {
pub fn compress_vec(&mut self, input: &mut [u8], output: &mut Vec<u8>) -> 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<D: Direction> Drop for Stream<D> {
#[inline]
fn drop(&mut self) {
unsafe {
let _ = <D as Direction>::destroy(&mut self.raw);
}
}
output
}

View file

@ -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<Vec<u8>, 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<Vec<u8>, 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<u8> {
miniz_stream::compress_to_vec_oxipng(data, zc, zw.into(), zs.into())
}
pub fn zopfli_deflate(data: &[u8]) -> Result<Vec<u8>, PngError> {

View file

@ -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<u8>,
/// Which zlib memory levels to try on the file (1-9)
///
/// Default: `9`
pub memory: HashSet<u8>,
/// 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<Vec<u8>, 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::<Vec<u8>>();
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()

View file

@ -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<Options, String> {
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();
}

View file

@ -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();