Dynamically set eval filters
This commit is contained in:
parent
a330998e4e
commit
301b413dc5
2 changed files with 18 additions and 15 deletions
|
|
@ -11,6 +11,7 @@ use crate::rayon;
|
|||
use crate::Deadline;
|
||||
#[cfg(feature = "parallel")]
|
||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||
use indexmap::IndexSet;
|
||||
use rayon::prelude::*;
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -18,10 +19,6 @@ use std::sync::atomic::AtomicUsize;
|
|||
use std::sync::atomic::Ordering::SeqCst;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Must use normal (lazy) compression, as faster ones (greedy) are not representative
|
||||
const STD_COMPRESSION: u8 = 5;
|
||||
const STD_FILTERS: [RowFilter; 2] = [RowFilter::None, RowFilter::MinSum];
|
||||
|
||||
pub struct Candidate {
|
||||
pub image: PngData,
|
||||
pub filter: RowFilter,
|
||||
|
|
@ -45,6 +42,8 @@ impl Candidate {
|
|||
/// Collect image versions and pick one that compresses best
|
||||
pub(crate) struct Evaluator {
|
||||
deadline: Arc<Deadline>,
|
||||
filters: IndexSet<RowFilter>,
|
||||
compression: u8,
|
||||
nth: AtomicUsize,
|
||||
best_candidate_size: Arc<AtomicMin>,
|
||||
/// images are sent to the caller thread for evaluation
|
||||
|
|
@ -56,11 +55,13 @@ pub(crate) struct Evaluator {
|
|||
}
|
||||
|
||||
impl Evaluator {
|
||||
pub fn new(deadline: Arc<Deadline>) -> Self {
|
||||
pub fn new(deadline: Arc<Deadline>, filters: IndexSet<RowFilter>, compression: u8) -> Self {
|
||||
#[cfg(feature = "parallel")]
|
||||
let eval_channel = unbounded();
|
||||
Self {
|
||||
deadline,
|
||||
filters,
|
||||
compression,
|
||||
best_candidate_size: Arc::new(AtomicMin::new(None)),
|
||||
nth: AtomicUsize::new(0),
|
||||
#[cfg(feature = "parallel")]
|
||||
|
|
@ -98,13 +99,15 @@ impl Evaluator {
|
|||
let nth = self.nth.fetch_add(1, SeqCst);
|
||||
// These clones are only cheap refcounts
|
||||
let deadline = self.deadline.clone();
|
||||
let filters = self.filters.clone();
|
||||
let compression = self.compression;
|
||||
let best_candidate_size = self.best_candidate_size.clone();
|
||||
// sends it off asynchronously for compression,
|
||||
// but results will be collected via the message queue
|
||||
#[cfg(feature = "parallel")]
|
||||
let eval_send = self.eval_channel.0.clone();
|
||||
rayon::spawn(move || {
|
||||
let filters_iter = STD_FILTERS.par_iter().with_max_len(1);
|
||||
let filters_iter = filters.par_iter().with_max_len(1);
|
||||
|
||||
// Updating of best result inside the parallel loop would require locks,
|
||||
// which are dangerous to do in side Rayon's loop.
|
||||
|
|
@ -116,7 +119,7 @@ impl Evaluator {
|
|||
}
|
||||
if let Ok(idat_data) = deflate::deflate(
|
||||
&image.filter_image(filter),
|
||||
STD_COMPRESSION,
|
||||
compression,
|
||||
&best_candidate_size,
|
||||
) {
|
||||
best_candidate_size.set_min(idat_data.len());
|
||||
|
|
|
|||
16
src/lib.rs
16
src/lib.rs
|
|
@ -484,22 +484,22 @@ fn optimize_png(
|
|||
|
||||
let mut filter = opts.filter.clone();
|
||||
|
||||
if opts.use_heuristics {
|
||||
if filter.is_empty() {
|
||||
// Heuristically determine which set of options to use
|
||||
let use_filter = if png.raw.ihdr.bit_depth.as_u8() >= 8
|
||||
if png.raw.ihdr.bit_depth.as_u8() >= 8
|
||||
&& png.raw.ihdr.color_type != colors::ColorType::Indexed
|
||||
{
|
||||
RowFilter::MinSum
|
||||
filter.insert(RowFilter::MinSum);
|
||||
} else {
|
||||
RowFilter::None
|
||||
filter.insert(RowFilter::None);
|
||||
};
|
||||
if filter.is_empty() {
|
||||
filter.insert(use_filter);
|
||||
}
|
||||
}
|
||||
|
||||
// Must use normal (lazy) compression, as faster ones (greedy) are not representative
|
||||
let eval_compression = 5;
|
||||
let eval_filters = indexset! {RowFilter::None, RowFilter::MinSum};
|
||||
// This will collect all versions of images and pick one that compresses best
|
||||
let eval = Evaluator::new(deadline.clone());
|
||||
let eval = Evaluator::new(deadline.clone(), eval_filters, eval_compression);
|
||||
perform_reductions(png.raw.clone(), opts, &deadline, &eval);
|
||||
let reduction_occurred = if let Some(result) = eval.get_best_candidate() {
|
||||
*png = result.image;
|
||||
|
|
|
|||
Loading…
Reference in a new issue