Merge branch 'master' into rm-unused-opts
This commit is contained in:
commit
4c6e9a6253
5 changed files with 45 additions and 30 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
|
@ -181,7 +181,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.23.2"
|
version = "0.23.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
@ -295,7 +295,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.12.0"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
@ -311,12 +311,11 @@ dependencies = [
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cloudflare-zlib 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cloudflare-zlib 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libdeflater 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libdeflater 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rgb 0.8.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rgb 0.8.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wild 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wild 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
@ -353,7 +352,7 @@ dependencies = [
|
||||||
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -478,7 +477,7 @@ dependencies = [
|
||||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
||||||
"checksum image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9062b90712d25bc6bb165d110aa59c6b47c849246e341e7b86a98daff9d49f60"
|
"checksum image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc5483f8d5afd3653b38a196c52294dcb239c3e1a5bade1990353ea13bcf387"
|
||||||
"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
|
"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
|
||||||
"checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
|
"checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
|
||||||
"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||||
|
|
@ -492,7 +491,7 @@ dependencies = [
|
||||||
"checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00"
|
"checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00"
|
||||||
"checksum num-rational 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "da4dc79f9e6c81bef96148c8f6b8e72ad4541caa4a24373e900a36da07de03a3"
|
"checksum num-rational 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "da4dc79f9e6c81bef96148c8f6b8e72ad4541caa4a24373e900a36da07de03a3"
|
||||||
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||||
"checksum png 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46060468187c21c00ffa2a920690b29997d7fd543f5a4d400461e4a7d4fccde8"
|
"checksum png 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46060468187c21c00ffa2a920690b29997d7fd543f5a4d400461e4a7d4fccde8"
|
||||||
"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
|
"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
|
||||||
"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
|
"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ bit-vec = "^0.6.0"
|
||||||
byteorder = "^1.0.0"
|
byteorder = "^1.0.0"
|
||||||
crc = "^1.2.0"
|
crc = "^1.2.0"
|
||||||
itertools = "^0.9.0"
|
itertools = "^0.9.0"
|
||||||
num_cpus = "^1.0.0"
|
|
||||||
zopfli = "^0.4.0"
|
zopfli = "^0.4.0"
|
||||||
miniz_oxide = "0.3"
|
miniz_oxide = "0.3"
|
||||||
rgb = "0.8.11"
|
rgb = "0.8.11"
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,15 @@ use crate::png::STD_WINDOW;
|
||||||
#[cfg(not(feature = "parallel"))]
|
#[cfg(not(feature = "parallel"))]
|
||||||
use crate::rayon;
|
use crate::rayon;
|
||||||
use crate::Deadline;
|
use crate::Deadline;
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
use rayon;
|
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
#[cfg(not(feature = "parallel"))]
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::atomic::Ordering::SeqCst;
|
use std::sync::atomic::Ordering::SeqCst;
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
use std::sync::mpsc::*;
|
use std::sync::mpsc::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
struct Candidate {
|
struct Candidate {
|
||||||
|
|
@ -46,30 +48,46 @@ pub(crate) struct Evaluator {
|
||||||
nth: AtomicUsize,
|
nth: AtomicUsize,
|
||||||
best_candidate_size: Arc<AtomicMin>,
|
best_candidate_size: Arc<AtomicMin>,
|
||||||
/// images are sent to the thread for evaluation
|
/// images are sent to the thread for evaluation
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
eval_send: SyncSender<Candidate>,
|
eval_send: SyncSender<Candidate>,
|
||||||
// the thread helps evaluate images asynchronously
|
// the thread helps evaluate images asynchronously
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
eval_thread: thread::JoinHandle<Option<Candidate>>,
|
eval_thread: thread::JoinHandle<Option<Candidate>>,
|
||||||
|
// in non-parallel mode, images are evaluated synchronously
|
||||||
|
#[cfg(not(feature = "parallel"))]
|
||||||
|
eval_best_candidate: RefCell<Option<Candidate>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluator {
|
impl Evaluator {
|
||||||
pub fn new(deadline: Arc<Deadline>) -> Self {
|
pub fn new(deadline: Arc<Deadline>) -> Self {
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
let (tx, rx) = sync_channel(4);
|
let (tx, rx) = sync_channel(4);
|
||||||
Self {
|
Self {
|
||||||
deadline,
|
deadline,
|
||||||
best_candidate_size: Arc::new(AtomicMin::new(None)),
|
best_candidate_size: Arc::new(AtomicMin::new(None)),
|
||||||
nth: AtomicUsize::new(0),
|
nth: AtomicUsize::new(0),
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
eval_send: tx,
|
eval_send: tx,
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
eval_thread: thread::spawn(move || rx.into_iter().min_by_key(Candidate::cmp_key)),
|
eval_thread: thread::spawn(move || rx.into_iter().min_by_key(Candidate::cmp_key)),
|
||||||
|
#[cfg(not(feature = "parallel"))]
|
||||||
|
eval_best_candidate: RefCell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for all evaluations to finish and return smallest reduction
|
/// Wait for all evaluations to finish and return smallest reduction
|
||||||
/// Or `None` if all reductions were worse than baseline.
|
/// Or `None` if all reductions were worse than baseline.
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
fn get_best_candidate(self) -> Option<Candidate> {
|
fn get_best_candidate(self) -> Option<Candidate> {
|
||||||
drop(self.eval_send); // disconnect the sender, breaking the loop in the thread
|
drop(self.eval_send); // disconnect the sender, breaking the loop in the thread
|
||||||
self.eval_thread.join().expect("eval thread")
|
self.eval_thread.join().expect("eval thread")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "parallel"))]
|
||||||
|
fn get_best_candidate(self) -> Option<Candidate> {
|
||||||
|
self.eval_best_candidate.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_result(self) -> Option<PngData> {
|
pub fn get_result(self) -> Option<PngData> {
|
||||||
self.get_best_candidate().map(|candidate| candidate.image)
|
self.get_best_candidate().map(|candidate| candidate.image)
|
||||||
}
|
}
|
||||||
|
|
@ -91,6 +109,7 @@ impl Evaluator {
|
||||||
let best_candidate_size = self.best_candidate_size.clone();
|
let best_candidate_size = self.best_candidate_size.clone();
|
||||||
// sends it off asynchronously for compression,
|
// sends it off asynchronously for compression,
|
||||||
// but results will be collected via the message queue
|
// but results will be collected via the message queue
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
let eval_send = self.eval_send.clone();
|
let eval_send = self.eval_send.clone();
|
||||||
rayon::spawn(move || {
|
rayon::spawn(move || {
|
||||||
let filters_iter = STD_FILTERS.par_iter().with_max_len(1);
|
let filters_iter = STD_FILTERS.par_iter().with_max_len(1);
|
||||||
|
|
@ -126,8 +145,19 @@ impl Evaluator {
|
||||||
nth,
|
nth,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
|
{
|
||||||
eval_send.send(new).expect("send");
|
eval_send.send(new).expect("send");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "parallel"))]
|
||||||
|
{
|
||||||
|
match &mut *self.eval_best_candidate.borrow_mut() {
|
||||||
|
Some(prev) if prev.cmp_key() < new.cmp_key() => {}
|
||||||
|
best => *best = Some(new),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/lib.rs
18
src/lib.rs
|
|
@ -13,7 +13,6 @@
|
||||||
#![warn(clippy::range_plus_one)]
|
#![warn(clippy::range_plus_one)]
|
||||||
#![allow(clippy::cognitive_complexity)]
|
#![allow(clippy::cognitive_complexity)]
|
||||||
|
|
||||||
use num_cpus;
|
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
extern crate rayon;
|
extern crate rayon;
|
||||||
#[cfg(not(feature = "parallel"))]
|
#[cfg(not(feature = "parallel"))]
|
||||||
|
|
@ -206,10 +205,6 @@ pub struct Options {
|
||||||
///
|
///
|
||||||
/// Default: `false`
|
/// Default: `false`
|
||||||
pub use_heuristics: bool,
|
pub use_heuristics: bool,
|
||||||
/// Number of threads to use
|
|
||||||
///
|
|
||||||
/// Default: number of CPU cores
|
|
||||||
pub threads: usize,
|
|
||||||
|
|
||||||
/// Maximum amount of time to spend on optimizations.
|
/// Maximum amount of time to spend on optimizations.
|
||||||
/// Further potential optimizations are skipped if the timeout is exceeded.
|
/// Further potential optimizations are skipped if the timeout is exceeded.
|
||||||
|
|
@ -313,7 +308,6 @@ impl Default for Options {
|
||||||
strip: Headers::None,
|
strip: Headers::None,
|
||||||
deflate: Deflaters::Zlib,
|
deflate: Deflaters::Zlib,
|
||||||
use_heuristics: false,
|
use_heuristics: false,
|
||||||
threads: num_cpus::get(),
|
|
||||||
timeout: None,
|
timeout: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -321,12 +315,6 @@ impl Default for Options {
|
||||||
|
|
||||||
/// Perform optimization on the input file using the options provided
|
/// Perform optimization on the input file using the options provided
|
||||||
pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<()> {
|
pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<()> {
|
||||||
// Initialize the thread pool with correct number of threads
|
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
let _ = rayon::ThreadPoolBuilder::new()
|
|
||||||
.num_threads(opts.threads)
|
|
||||||
.build_global();
|
|
||||||
|
|
||||||
// Read in the file and try to decode as PNG.
|
// Read in the file and try to decode as PNG.
|
||||||
if opts.verbosity.is_some() {
|
if opts.verbosity.is_some() {
|
||||||
eprintln!("Processing: {}", input);
|
eprintln!("Processing: {}", input);
|
||||||
|
|
@ -421,12 +409,6 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<(
|
||||||
/// Perform optimization on the input file using the options provided, where the file is already
|
/// Perform optimization on the input file using the options provided, where the file is already
|
||||||
/// loaded in-memory
|
/// loaded in-memory
|
||||||
pub fn optimize_from_memory(data: &[u8], opts: &Options) -> PngResult<Vec<u8>> {
|
pub fn optimize_from_memory(data: &[u8], opts: &Options) -> PngResult<Vec<u8>> {
|
||||||
// Initialize the thread pool with correct number of threads
|
|
||||||
#[cfg(feature = "parallel")]
|
|
||||||
let _ = rayon::ThreadPoolBuilder::new()
|
|
||||||
.num_threads(opts.threads)
|
|
||||||
.build_global();
|
|
||||||
|
|
||||||
// Read in the file and try to decode as PNG.
|
// Read in the file and try to decode as PNG.
|
||||||
if opts.verbosity.is_some() {
|
if opts.verbosity.is_some() {
|
||||||
eprintln!("Processing from memory");
|
eprintln!("Processing from memory");
|
||||||
|
|
|
||||||
|
|
@ -486,7 +486,12 @@ fn parse_opts_into_struct(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(x) = matches.value_of("threads") {
|
if let Some(x) = matches.value_of("threads") {
|
||||||
opts.threads = x.parse::<usize>().unwrap();
|
let threads = x.parse::<usize>().unwrap();
|
||||||
|
|
||||||
|
rayon::ThreadPoolBuilder::new()
|
||||||
|
.num_threads(threads)
|
||||||
|
.build_global()
|
||||||
|
.map_err(|err| err.to_string())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((out_file, out_dir, opts))
|
Ok((out_file, out_dir, opts))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue