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 test;
|
||||
|
||||
use std::{num::NonZeroU8, path::PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use oxipng::{internal_tests::*, *};
|
||||
use test::Bencher;
|
||||
|
||||
const DEFAULT_ZOPFLI_ITERATIONS: NonZeroU8 = NonZeroU8::new(15).unwrap();
|
||||
|
||||
#[bench]
|
||||
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 png = PngData::new(&input, &Options::default()).unwrap();
|
||||
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
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};
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ speed up compression for large files. This option requires '--zopfli' to be set.
|
|||
.long("zi")
|
||||
.value_name("iterations")
|
||||
.default_value("15")
|
||||
.value_parser(1..=255)
|
||||
.value_parser(value_parser!(NonZeroU64))
|
||||
.requires("zopfli"),
|
||||
)
|
||||
.arg(
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
mod deflater;
|
||||
#[cfg(feature = "zopfli")]
|
||||
use std::num::NonZeroU8;
|
||||
use std::{fmt, fmt::Display};
|
||||
|
||||
pub use deflater::{crc32, deflate, inflate};
|
||||
|
||||
use crate::{PngError, PngResult};
|
||||
use std::{fmt, fmt::Display};
|
||||
|
||||
#[cfg(feature = "zopfli")]
|
||||
mod zopfli_oxipng;
|
||||
#[cfg(feature = "zopfli")]
|
||||
pub use zopfli::Options as ZopfliOptions;
|
||||
#[cfg(feature = "zopfli")]
|
||||
pub use zopfli_oxipng::deflate as zopfli_deflate;
|
||||
|
||||
/// DEFLATE algorithms supported by oxipng (for use in [`Options`][crate::Options])
|
||||
|
|
@ -21,12 +21,7 @@ pub enum Deflater {
|
|||
},
|
||||
#[cfg(feature = "zopfli")]
|
||||
/// Use the better but slower Zopfli implementation
|
||||
Zopfli {
|
||||
/// 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,
|
||||
},
|
||||
Zopfli(ZopfliOptions),
|
||||
}
|
||||
|
||||
impl Deflater {
|
||||
|
|
@ -34,7 +29,7 @@ impl Deflater {
|
|||
let compressed = match self {
|
||||
Self::Libdeflater { compression } => deflate(data, compression, max_size)?,
|
||||
#[cfg(feature = "zopfli")]
|
||||
Self::Zopfli { iterations } => zopfli_deflate(data, iterations)?,
|
||||
Self::Zopfli(options) => zopfli_deflate(data, options)?,
|
||||
};
|
||||
if let Some(max) = max_size {
|
||||
if compressed.len() > max {
|
||||
|
|
@ -51,7 +46,7 @@ impl Display for Deflater {
|
|||
match self {
|
||||
Self::Libdeflater { compression } => write!(f, "zc = {compression}"),
|
||||
#[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};
|
||||
|
||||
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 options = zopfli::Options {
|
||||
iteration_count: iterations.into(),
|
||||
..Default::default()
|
||||
};
|
||||
// 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.
|
||||
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::*;
|
||||
pub use rgb::{RGB16, RGBA8};
|
||||
|
||||
#[cfg(feature = "zopfli")]
|
||||
pub use crate::deflate::ZopfliOptions;
|
||||
pub use crate::{
|
||||
colors::{BitDepth, ColorType},
|
||||
deflate::Deflater,
|
||||
|
|
|
|||
13
src/main.rs
13
src/main.rs
|
|
@ -17,7 +17,7 @@
|
|||
mod rayon;
|
||||
|
||||
#[cfg(feature = "zopfli")]
|
||||
use std::num::NonZeroU8;
|
||||
use std::num::NonZeroU64;
|
||||
use std::{
|
||||
ffi::OsString, fs::DirBuilder, io::Write, path::PathBuf, process::ExitCode, time::Duration,
|
||||
};
|
||||
|
|
@ -26,6 +26,8 @@ use clap::ArgMatches;
|
|||
mod cli;
|
||||
use indexmap::IndexSet;
|
||||
use log::{Level, LevelFilter, error, warn};
|
||||
#[cfg(feature = "zopfli")]
|
||||
use oxipng::ZopfliOptions;
|
||||
use oxipng::{Deflater, FilterStrategy, InFile, Options, OutFile, PngError, StripChunks};
|
||||
use rayon::prelude::*;
|
||||
|
||||
|
|
@ -331,10 +333,11 @@ fn parse_opts_into_struct(
|
|||
|
||||
#[cfg(feature = "zopfli")]
|
||||
if matches.get_flag("zopfli") {
|
||||
let iterations = *matches.get_one::<i64>("iterations").unwrap();
|
||||
opts.deflater = Deflater::Zopfli {
|
||||
iterations: NonZeroU8::new(iterations as u8).unwrap(),
|
||||
};
|
||||
let iteration_count = *matches.get_one::<NonZeroU64>("iterations").unwrap();
|
||||
opts.deflater = Deflater::Zopfli(ZopfliOptions {
|
||||
iteration_count,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
if let (Deflater::Libdeflater { compression }, Some(x)) =
|
||||
(&mut opts.deflater, matches.get_one::<i64>("compression"))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
#[cfg(feature = "zopfli")]
|
||||
use std::num::NonZeroU8;
|
||||
use std::{
|
||||
fs::remove_file,
|
||||
path::{Path, PathBuf},
|
||||
|
|
@ -641,9 +639,7 @@ fn scale_16() {
|
|||
fn zopfli_mode() {
|
||||
let input = PathBuf::from("tests/files/zopfli_mode.png");
|
||||
let (output, mut opts) = get_opts(&input);
|
||||
opts.deflater = Deflater::Zopfli {
|
||||
iterations: NonZeroU8::new(15).unwrap(),
|
||||
};
|
||||
opts.deflater = Deflater::Zopfli(ZopfliOptions::default());
|
||||
|
||||
test_it_converts(
|
||||
input,
|
||||
|
|
|
|||
Loading…
Reference in a new issue