Use ZopfliOptions for Zopfli Deflater
This commit is contained in:
parent
79743a3b48
commit
8a5a3ab69e
7 changed files with 27 additions and 39 deletions
|
|
@ -3,20 +3,18 @@
|
||||||
extern crate oxipng;
|
extern crate oxipng;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use std::{num::NonZeroU8, path::PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use oxipng::{internal_tests::*, *};
|
use oxipng::{internal_tests::*, *};
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
const DEFAULT_ZOPFLI_ITERATIONS: NonZeroU8 = NonZeroU8::new(15).unwrap();
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn zopfli_16_bits_strategy_0(b: &mut Bencher) {
|
fn zopfli_16_bits_strategy_0(b: &mut Bencher) {
|
||||||
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
|
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
|
||||||
let png = PngData::new(&input, &Options::default()).unwrap();
|
let png = PngData::new(&input, &Options::default()).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
zopfli_deflate(png.raw.data.as_ref(), DEFAULT_ZOPFLI_ITERATIONS).ok();
|
zopfli_deflate(png.raw.data.as_ref(), ZopfliOptions::default()).ok();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,7 +24,7 @@ fn zopfli_8_bits_strategy_0(b: &mut Bencher) {
|
||||||
let png = PngData::new(&input, &Options::default()).unwrap();
|
let png = PngData::new(&input, &Options::default()).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
zopfli_deflate(png.raw.data.as_ref(), DEFAULT_ZOPFLI_ITERATIONS).ok();
|
zopfli_deflate(png.raw.data.as_ref(), ZopfliOptions::default()).ok();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,7 +36,7 @@ fn zopfli_4_bits_strategy_0(b: &mut Bencher) {
|
||||||
let png = PngData::new(&input, &Options::default()).unwrap();
|
let png = PngData::new(&input, &Options::default()).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
zopfli_deflate(png.raw.data.as_ref(), DEFAULT_ZOPFLI_ITERATIONS).ok();
|
zopfli_deflate(png.raw.data.as_ref(), ZopfliOptions::default()).ok();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,7 +48,7 @@ fn zopfli_2_bits_strategy_0(b: &mut Bencher) {
|
||||||
let png = PngData::new(&input, &Options::default()).unwrap();
|
let png = PngData::new(&input, &Options::default()).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
zopfli_deflate(png.raw.data.as_ref(), DEFAULT_ZOPFLI_ITERATIONS).ok();
|
zopfli_deflate(png.raw.data.as_ref(), ZopfliOptions::default()).ok();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,6 +60,6 @@ fn zopfli_1_bits_strategy_0(b: &mut Bencher) {
|
||||||
let png = PngData::new(&input, &Options::default()).unwrap();
|
let png = PngData::new(&input, &Options::default()).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
zopfli_deflate(png.raw.data.as_ref(), DEFAULT_ZOPFLI_ITERATIONS).ok();
|
zopfli_deflate(png.raw.data.as_ref(), ZopfliOptions::default()).ok();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::path::PathBuf;
|
use std::{num::NonZeroU64, path::PathBuf};
|
||||||
|
|
||||||
use clap::{Arg, ArgAction, Command, builder::ArgPredicate, value_parser};
|
use clap::{Arg, ArgAction, Command, builder::ArgPredicate, value_parser};
|
||||||
|
|
||||||
|
|
@ -337,7 +337,7 @@ speed up compression for large files. This option requires '--zopfli' to be set.
|
||||||
.long("zi")
|
.long("zi")
|
||||||
.value_name("iterations")
|
.value_name("iterations")
|
||||||
.default_value("15")
|
.default_value("15")
|
||||||
.value_parser(1..=255)
|
.value_parser(value_parser!(NonZeroU64))
|
||||||
.requires("zopfli"),
|
.requires("zopfli"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
mod deflater;
|
mod deflater;
|
||||||
#[cfg(feature = "zopfli")]
|
|
||||||
use std::num::NonZeroU8;
|
|
||||||
use std::{fmt, fmt::Display};
|
|
||||||
|
|
||||||
pub use deflater::{crc32, deflate, inflate};
|
pub use deflater::{crc32, deflate, inflate};
|
||||||
|
|
||||||
use crate::{PngError, PngResult};
|
use crate::{PngError, PngResult};
|
||||||
|
use std::{fmt, fmt::Display};
|
||||||
|
|
||||||
#[cfg(feature = "zopfli")]
|
#[cfg(feature = "zopfli")]
|
||||||
mod zopfli_oxipng;
|
mod zopfli_oxipng;
|
||||||
#[cfg(feature = "zopfli")]
|
#[cfg(feature = "zopfli")]
|
||||||
|
pub use zopfli::Options as ZopfliOptions;
|
||||||
|
#[cfg(feature = "zopfli")]
|
||||||
pub use zopfli_oxipng::deflate as zopfli_deflate;
|
pub use zopfli_oxipng::deflate as zopfli_deflate;
|
||||||
|
|
||||||
/// DEFLATE algorithms supported by oxipng (for use in [`Options`][crate::Options])
|
/// DEFLATE algorithms supported by oxipng (for use in [`Options`][crate::Options])
|
||||||
|
|
@ -21,12 +21,7 @@ pub enum Deflater {
|
||||||
},
|
},
|
||||||
#[cfg(feature = "zopfli")]
|
#[cfg(feature = "zopfli")]
|
||||||
/// Use the better but slower Zopfli implementation
|
/// Use the better but slower Zopfli implementation
|
||||||
Zopfli {
|
Zopfli(ZopfliOptions),
|
||||||
/// The number of compression iterations to do. 15 iterations are fine
|
|
||||||
/// for small files, but bigger files will need to be compressed with
|
|
||||||
/// less iterations, or else they will be too slow.
|
|
||||||
iterations: NonZeroU8,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deflater {
|
impl Deflater {
|
||||||
|
|
@ -34,7 +29,7 @@ impl Deflater {
|
||||||
let compressed = match self {
|
let compressed = match self {
|
||||||
Self::Libdeflater { compression } => deflate(data, compression, max_size)?,
|
Self::Libdeflater { compression } => deflate(data, compression, max_size)?,
|
||||||
#[cfg(feature = "zopfli")]
|
#[cfg(feature = "zopfli")]
|
||||||
Self::Zopfli { iterations } => zopfli_deflate(data, iterations)?,
|
Self::Zopfli(options) => zopfli_deflate(data, options)?,
|
||||||
};
|
};
|
||||||
if let Some(max) = max_size {
|
if let Some(max) = max_size {
|
||||||
if compressed.len() > max {
|
if compressed.len() > max {
|
||||||
|
|
@ -51,7 +46,7 @@ impl Display for Deflater {
|
||||||
match self {
|
match self {
|
||||||
Self::Libdeflater { compression } => write!(f, "zc = {compression}"),
|
Self::Libdeflater { compression } => write!(f, "zc = {compression}"),
|
||||||
#[cfg(feature = "zopfli")]
|
#[cfg(feature = "zopfli")]
|
||||||
Self::Zopfli { iterations } => write!(f, "zopfli, zi = {iterations}"),
|
Self::Zopfli(options) => write!(f, "zopfli, zi = {}", options.iteration_count),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,7 @@
|
||||||
use std::num::NonZeroU8;
|
|
||||||
|
|
||||||
use crate::{PngError, PngResult};
|
use crate::{PngError, PngResult};
|
||||||
|
|
||||||
pub fn deflate(data: &[u8], iterations: NonZeroU8) -> PngResult<Vec<u8>> {
|
pub fn deflate(data: &[u8], options: zopfli::Options) -> PngResult<Vec<u8>> {
|
||||||
let mut output = Vec::with_capacity(data.len());
|
let mut output = Vec::with_capacity(data.len());
|
||||||
let options = zopfli::Options {
|
|
||||||
iteration_count: iterations.into(),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
// Since Rust v1.74, passing &[u8] directly into zopfli causes a regression in compressed size
|
// Since Rust v1.74, passing &[u8] directly into zopfli causes a regression in compressed size
|
||||||
// for some files. Wrapping the slice in another Read implementer such as Box fixes it for now.
|
// for some files. Wrapping the slice in another Read implementer such as Box fixes it for now.
|
||||||
match zopfli::compress(options, zopfli::Format::Zlib, Box::new(data), &mut output) {
|
match zopfli::compress(options, zopfli::Format::Zlib, Box::new(data), &mut output) {
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ use log::{debug, info, trace, warn};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
pub use rgb::{RGB16, RGBA8};
|
pub use rgb::{RGB16, RGBA8};
|
||||||
|
|
||||||
|
#[cfg(feature = "zopfli")]
|
||||||
|
pub use crate::deflate::ZopfliOptions;
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
colors::{BitDepth, ColorType},
|
colors::{BitDepth, ColorType},
|
||||||
deflate::Deflater,
|
deflate::Deflater,
|
||||||
|
|
|
||||||
13
src/main.rs
13
src/main.rs
|
|
@ -17,7 +17,7 @@
|
||||||
mod rayon;
|
mod rayon;
|
||||||
|
|
||||||
#[cfg(feature = "zopfli")]
|
#[cfg(feature = "zopfli")]
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZeroU64;
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsString, fs::DirBuilder, io::Write, path::PathBuf, process::ExitCode, time::Duration,
|
ffi::OsString, fs::DirBuilder, io::Write, path::PathBuf, process::ExitCode, time::Duration,
|
||||||
};
|
};
|
||||||
|
|
@ -26,6 +26,8 @@ use clap::ArgMatches;
|
||||||
mod cli;
|
mod cli;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use log::{Level, LevelFilter, error, warn};
|
use log::{Level, LevelFilter, error, warn};
|
||||||
|
#[cfg(feature = "zopfli")]
|
||||||
|
use oxipng::ZopfliOptions;
|
||||||
use oxipng::{Deflater, FilterStrategy, InFile, Options, OutFile, PngError, StripChunks};
|
use oxipng::{Deflater, FilterStrategy, InFile, Options, OutFile, PngError, StripChunks};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
|
@ -331,10 +333,11 @@ fn parse_opts_into_struct(
|
||||||
|
|
||||||
#[cfg(feature = "zopfli")]
|
#[cfg(feature = "zopfli")]
|
||||||
if matches.get_flag("zopfli") {
|
if matches.get_flag("zopfli") {
|
||||||
let iterations = *matches.get_one::<i64>("iterations").unwrap();
|
let iteration_count = *matches.get_one::<NonZeroU64>("iterations").unwrap();
|
||||||
opts.deflater = Deflater::Zopfli {
|
opts.deflater = Deflater::Zopfli(ZopfliOptions {
|
||||||
iterations: NonZeroU8::new(iterations as u8).unwrap(),
|
iteration_count,
|
||||||
};
|
..Default::default()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if let (Deflater::Libdeflater { compression }, Some(x)) =
|
if let (Deflater::Libdeflater { compression }, Some(x)) =
|
||||||
(&mut opts.deflater, matches.get_one::<i64>("compression"))
|
(&mut opts.deflater, matches.get_one::<i64>("compression"))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
#[cfg(feature = "zopfli")]
|
|
||||||
use std::num::NonZeroU8;
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::remove_file,
|
fs::remove_file,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
|
@ -641,9 +639,7 @@ fn scale_16() {
|
||||||
fn zopfli_mode() {
|
fn zopfli_mode() {
|
||||||
let input = PathBuf::from("tests/files/zopfli_mode.png");
|
let input = PathBuf::from("tests/files/zopfli_mode.png");
|
||||||
let (output, mut opts) = get_opts(&input);
|
let (output, mut opts) = get_opts(&input);
|
||||||
opts.deflater = Deflater::Zopfli {
|
opts.deflater = Deflater::Zopfli(ZopfliOptions::default());
|
||||||
iterations: NonZeroU8::new(15).unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
test_it_converts(
|
test_it_converts(
|
||||||
input,
|
input,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue