Make Rayon an optional dependency (#112)

On WebAssembly, Rayon does not work (thread pool fails to initialize since threads are stubbed out).
This commit is contained in:
myfreeweb 2018-07-06 17:50:36 +03:00 committed by Josh Holmer
parent 2d303f5dc2
commit ae65e4be8d
3 changed files with 44 additions and 15 deletions

View file

@ -32,10 +32,13 @@ byteorder = "^1.0.0"
crc = "^1.2.0"
itertools = "^0.7.7"
num_cpus = "^1.0.0"
rayon = "^1.0.0"
zopfli = "^0.3.4"
miniz_oxide = "0.1.2"
[dependencies.rayon]
optional = true
version = "^1.0.0"
[dependencies.clap]
optional = true
version = "^2.10.0"
@ -62,7 +65,8 @@ binary = [
"clap",
"wild",
]
default = ["binary"]
default = ["binary", "parallel"]
parallel = ["rayon"]
cfzlib = ["cloudflare-zlib-sys"]
dev = [
"nightly-binary",

View file

@ -8,6 +8,7 @@ extern crate image;
extern crate itertools;
extern crate miniz_oxide;
extern crate num_cpus;
#[cfg(feature = "parallel")]
extern crate rayon;
extern crate zopfli;
#[cfg(feature = "cfzlib")]
@ -15,6 +16,7 @@ extern crate cloudflare_zlib_sys;
use image::{DynamicImage, GenericImage, ImageFormat, Pixel};
use png::PngData;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use std::collections::{HashMap, HashSet};
use std::fs::{copy, File};
@ -277,7 +279,9 @@ impl Default for Options {
/// Perform optimization on the input file using the options provided
pub fn optimize(input_path: &Path, opts: &Options) -> Result<(), PngError> {
// Initialize the thread pool with correct number of threads
#[cfg(feature = "parallel")]
let thread_count = opts.threads;
#[cfg(feature = "parallel")]
let _ = rayon::ThreadPoolBuilder::new()
.num_threads(thread_count)
.build_global();
@ -356,7 +360,9 @@ pub fn optimize(input_path: &Path, opts: &Options) -> Result<(), PngError> {
/// loaded in-memory
pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result<Vec<u8>, PngError> {
// Initialize the thread pool with correct number of threads
#[cfg(feature = "parallel")]
let thread_count = opts.threads;
#[cfg(feature = "parallel")]
let _ = rayon::ThreadPoolBuilder::new()
.num_threads(thread_count)
.build_global();
@ -483,9 +489,11 @@ fn optimize_png(
}
}
let filters: HashMap<u8, Vec<u8>> = filter
.par_iter()
.with_max_len(1)
#[cfg(feature = "parallel")]
let filter_iter = filter.par_iter().with_max_len(1);
#[cfg(not(feature = "parallel"))]
let filter_iter = filter.iter();
let filters: HashMap<u8, Vec<u8>> = filter_iter
.map(|f| {
let png = png.clone();
(*f, png.filter_image(*f))
@ -496,9 +504,11 @@ fn optimize_png(
let added_interlacing = opts.interlace == Some(1) && original_png.ihdr_data.interlaced == 0;
let best_size = AtomicMin::new(if opts.force {None} else {Some(original_len)});
let best: Option<TrialWithData> = results
.into_par_iter()
.with_max_len(1)
#[cfg(feature = "parallel")]
let results_iter = results.into_par_iter().with_max_len(1);
#[cfg(not(feature = "parallel"))]
let results_iter = results.into_iter();
let best = results_iter
.filter_map(|trial| {
let filtered = &filters[&trial.filter];
let new_idat = if opts.deflate == Deflaters::Zlib {
@ -540,8 +550,18 @@ fn optimize_png(
} else {
None
}
})
});
#[cfg(feature = "parallel")]
let best: Option<TrialWithData> = best
.reduce_with(|i, j| if i.1.len() <= j.1.len() { i } else { j });
#[cfg(not(feature = "parallel"))]
let best: Option<TrialWithData> = best.fold(None, |i, j| {
if let Some(i) = i {
if i.1.len() <= j.1.len() { Some(i) } else { Some(j) }
} else {
Some(j)
}
});
if let Some(better) = best {
png.idat_data = better.1;

View file

@ -15,6 +15,7 @@ use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::iter::Iterator;
use std::path::Path;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use atomicmin::AtomicMin;
@ -605,15 +606,19 @@ impl PngData {
assert!(!alphas.is_empty());
let alphas = alphas.iter().collect::<Vec<_>>();
let best_size = AtomicMin::new(None);
let best = alphas
.par_iter()
.with_max_len(1)
#[cfg(feature = "parallel")]
let alphas_iter = alphas.par_iter().with_max_len(1);
#[cfg(not(feature = "parallel"))]
let alphas_iter = alphas.iter();
let best = alphas_iter
.filter_map(|&alpha| {
let mut image = self.clone();
image.reduce_alpha_channel(*alpha);
STD_FILTERS
.par_iter()
.with_max_len(1)
#[cfg(feature = "parallel")]
let filters_iter = STD_FILTERS.par_iter().with_max_len(1);
#[cfg(not(feature = "parallel"))]
let filters_iter = STD_FILTERS.iter();
filters_iter
.filter_map(|f| {
deflate::deflate(
&image.filter_image(*f),