diff --git a/benches/zopfli.rs b/benches/zopfli.rs index 9fe9e8b6..23dd67bb 100644 --- a/benches/zopfli.rs +++ b/benches/zopfli.rs @@ -9,12 +9,7 @@ use std::num::NonZeroU8; use std::path::PathBuf; use test::Bencher; - -const DEFAULT_DEFLATER: BufferedZopfliDeflater = BufferedZopfliDeflater::new( - // SAFETY: trivially safe. Stopgap solution until const unwrap is stabilized. - unsafe { NonZeroU8::new_unchecked(15) }, - 4 * 1024 * 1024 -); +const DEFAULT_DEFLATER: BufferedZopfliDeflater = BufferedZopfliDeflater::const_default(); #[bench] fn zopfli_16_bits_strategy_0(b: &mut Bencher) { @@ -23,7 +18,9 @@ fn zopfli_16_bits_strategy_0(b: &mut Bencher) { let max_size = AtomicMin::new(Some(png.idat_data.len())); b.iter(|| { - DEFAULT_DEFLATER.deflate(png.raw.data.as_ref(), &max_size).ok(); + DEFAULT_DEFLATER + .deflate(png.raw.data.as_ref(), &max_size) + .ok(); }); } @@ -34,7 +31,9 @@ fn zopfli_8_bits_strategy_0(b: &mut Bencher) { let max_size = AtomicMin::new(Some(png.idat_data.len())); b.iter(|| { - DEFAULT_DEFLATER.deflate(png.raw.data.as_ref(), &max_size).ok(); + DEFAULT_DEFLATER + .deflate(png.raw.data.as_ref(), &max_size) + .ok(); }); } @@ -47,7 +46,9 @@ fn zopfli_4_bits_strategy_0(b: &mut Bencher) { let max_size = AtomicMin::new(Some(png.idat_data.len())); b.iter(|| { - DEFAULT_DEFLATER.deflate(png.raw.data.as_ref(), &max_size).ok(); + DEFAULT_DEFLATER + .deflate(png.raw.data.as_ref(), &max_size) + .ok(); }); } @@ -60,7 +61,9 @@ fn zopfli_2_bits_strategy_0(b: &mut Bencher) { let max_size = AtomicMin::new(Some(png.idat_data.len())); b.iter(|| { - DEFAULT_DEFLATER.deflate(png.raw.data.as_ref(), &max_size).ok(); + DEFAULT_DEFLATER + .deflate(png.raw.data.as_ref(), &max_size) + .ok(); }); } @@ -73,6 +76,8 @@ fn zopfli_1_bits_strategy_0(b: &mut Bencher) { let max_size = AtomicMin::new(Some(png.idat_data.len())); b.iter(|| { - DEFAULT_DEFLATER.deflate(png.raw.data.as_ref(), &max_size).ok(); + DEFAULT_DEFLATER + .deflate(png.raw.data.as_ref(), &max_size) + .ok(); }); } diff --git a/src/deflate/mod.rs b/src/deflate/mod.rs index 19281e14..a678e0e2 100644 --- a/src/deflate/mod.rs +++ b/src/deflate/mod.rs @@ -4,8 +4,8 @@ use crate::{PngError, PngResult}; pub use deflater::crc32; pub use deflater::deflate; pub use deflater::inflate; -use std::{fmt, fmt::Display, io}; use std::io::{BufWriter, Cursor, Write}; +use std::{fmt, fmt::Display, io}; #[cfg(feature = "zopfli")] use std::num::NonZeroU8; @@ -61,29 +61,60 @@ pub struct BufferedZopfliDeflater { iterations: NonZeroU8, input_buffer_size: usize, output_buffer_size: usize, - max_block_splits: u16 + max_block_splits: u16, } +#[cfg(feature = "zopfli")] impl BufferedZopfliDeflater { - pub const fn new(iterations: NonZeroU8, - input_buffer_size: usize, - output_buffer_size: usize, - max_block_splits: u16) -> Self { - BufferedZopfliDeflater {iterations, input_buffer_size, output_buffer_size, max_block_splits } + pub const fn new( + iterations: NonZeroU8, + input_buffer_size: usize, + output_buffer_size: usize, + max_block_splits: u16, + ) -> Self { + BufferedZopfliDeflater { + iterations, + input_buffer_size, + output_buffer_size, + max_block_splits, + } + } + + pub const fn const_default() -> Self { + BufferedZopfliDeflater { + // SAFETY: trivially safe. Stopgap solution until const unwrap is stabilized. + iterations: unsafe { NonZeroU8::new_unchecked(15) }, + input_buffer_size: 1024 * 1024, + output_buffer_size: 64 * 1024, + max_block_splits: 15, + } + } +} + +#[cfg(feature = "zopfli")] +impl Default for BufferedZopfliDeflater { + fn default() -> Self { + Self::const_default() } } #[cfg(feature = "zopfli")] impl Deflater for BufferedZopfliDeflater { fn deflate(&self, data: &[u8], max_size: &AtomicMin) -> PngResult> { + #[allow(clippy::needless_update)] let options = Options { iteration_count: self.iterations, maximum_block_splits: self.max_block_splits, - ..Default::default() + ..Default::default() // for forward compatibility }; - let mut buffer = BufWriter::with_capacity(self.input_buffer_size, - DeflateEncoder::new( - options, Default::default(), Cursor::new(Vec::new()))); + let mut buffer = BufWriter::with_capacity( + self.input_buffer_size, + DeflateEncoder::new( + options, + Default::default(), + Cursor::new(Vec::with_capacity(self.output_buffer_size)), + ), + ); let result = (|| -> io::Result> { buffer.write_all(data)?; Ok(buffer.into_inner()?.finish()?.into_inner()) diff --git a/src/headers.rs b/src/headers.rs index a213f79f..06671437 100644 --- a/src/headers.rs +++ b/src/headers.rs @@ -1,5 +1,5 @@ use crate::colors::{BitDepth, ColorType}; -use crate::deflate::{crc32, Deflater, inflate}; +use crate::deflate::{crc32, inflate, Deflater}; use crate::error::PngError; use crate::interlace::Interlacing; use crate::AtomicMin; diff --git a/src/lib.rs b/src/lib.rs index d0f64167..e2b32b77 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,7 @@ use std::sync::Arc; use std::time::{Duration, Instant}; pub use crate::colors::{BitDepth, ColorType}; +use crate::deflate::Deflater; pub use crate::deflate::Deflaters; pub use crate::error::PngError; pub use crate::filters::RowFilter; @@ -48,7 +49,6 @@ pub use crate::headers::StripChunks; pub use crate::interlace::Interlacing; pub use indexmap::{indexset, IndexSet}; pub use rgb::{RGB16, RGBA8}; -use crate::deflate::Deflater; mod atomicmin; mod colors; @@ -387,11 +387,13 @@ impl RawImage { } /// Create an optimized png from the raw image data using the options provided - pub fn create_optimized_png - (&self, opts: &Options, deflater: &T) -> PngResult> { + pub fn create_optimized_png( + &self, + opts: &Options, + deflater: &T, + ) -> PngResult> { let deadline = Arc::new(Deadline::new(opts.timeout)); - let mut png = optimize_raw(self.png.clone(), - opts, deadline, None, deflater) + let mut png = optimize_raw(self.png.clone(), opts, deadline, None, deflater) .ok_or_else(|| PngError::new("Failed to optimize input data"))?; // Process aux chunks @@ -572,8 +574,7 @@ fn optimize_png( } else { Some(png.estimated_output_size()) }; - if let Some(new_png) = optimize_raw(raw.clone(), opts, deadline, max_size, - &opts.deflate) { + if let Some(new_png) = optimize_raw(raw.clone(), opts, deadline, max_size, &opts.deflate) { png.raw = new_png.raw; png.idat_data = new_png.idat_data; } @@ -623,7 +624,7 @@ fn optimize_raw( opts: &Options, deadline: Arc, max_size: Option, - deflater: &T + deflater: &T, ) -> Option { // Must use normal (lazy) compression, as faster ones (greedy) are not representative let eval_compression = 5; @@ -765,7 +766,7 @@ fn perform_trial( opts: &Options, filter: RowFilter, best_size: &AtomicMin, - deflater: &T + deflater: &T, ) -> Option { let result = deflater.deflate(filtered, best_size); match result { @@ -782,11 +783,11 @@ fn perform_trial( } Err(PngError::DeflatedDataTooLong(bytes)) => { trace!( - " zc = {} f = {:8} >{} bytes", - opts.deflate, - filter, - bytes, - ); + " zc = {} f = {:8} >{} bytes", + opts.deflate, + filter, + bytes, + ); None } Err(e) => {