parent
391c04ea62
commit
08e6d42021
5 changed files with 43 additions and 30 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,3 +2,4 @@ target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
*.bk
|
*.bk
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
*.out.png
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ bit-vec = "^0.4.2"
|
||||||
byteorder = "^0.4.0"
|
byteorder = "^0.4.0"
|
||||||
clap = "^1.5.4"
|
clap = "^1.5.4"
|
||||||
crc = "^1.0.0"
|
crc = "^1.0.0"
|
||||||
|
crossbeam = "^0.2.1"
|
||||||
libc = "^0.2.4"
|
libc = "^0.2.4"
|
||||||
libz-sys = "^1.0.0"
|
libz-sys = "^1.0.0"
|
||||||
regex = "^0.1.8"
|
regex = "^0.1.8"
|
||||||
|
|
|
||||||
65
src/lib.rs
65
src/lib.rs
|
|
@ -1,6 +1,7 @@
|
||||||
extern crate bit_vec;
|
extern crate bit_vec;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate crc;
|
extern crate crc;
|
||||||
|
extern crate crossbeam;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate libz_sys;
|
extern crate libz_sys;
|
||||||
|
|
||||||
|
|
@ -13,6 +14,7 @@ use std::io::BufWriter;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub mod deflate {
|
pub mod deflate {
|
||||||
pub mod deflate;
|
pub mod deflate;
|
||||||
|
|
@ -118,42 +120,51 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
|
||||||
if opts.idat_recoding || something_changed {
|
if opts.idat_recoding || something_changed {
|
||||||
// Go through selected permutations and determine the best
|
// Go through selected permutations and determine the best
|
||||||
let mut best: Option<(u8, u8, u8, u8)> = None;
|
let mut best: Option<(u8, u8, u8, u8)> = None;
|
||||||
|
let scoped_idat = Arc::new(png.idat_data.clone());
|
||||||
let combinations = opts.filter.len() * opts.compression.len() * opts.memory.len() *
|
let combinations = opts.filter.len() * opts.compression.len() * opts.memory.len() *
|
||||||
opts.strategies.len();
|
opts.strategies.len();
|
||||||
println!("Trying: {} combinations", combinations);
|
println!("Trying: {} combinations", combinations);
|
||||||
// TODO: Multithreading
|
crossbeam::scope(|scope| {
|
||||||
for f in &opts.filter {
|
for f in &opts.filter {
|
||||||
let filtered = png.filter_image(*f);
|
let filtered = png.filter_image(*f);
|
||||||
for zc in &opts.compression {
|
for zc in &opts.compression {
|
||||||
for zm in &opts.memory {
|
for zm in &opts.memory {
|
||||||
for zs in &opts.strategies {
|
for zs in &opts.strategies {
|
||||||
let new_idat = match deflate::deflate::deflate(&filtered,
|
let moved_png = png.clone();
|
||||||
*zc,
|
let mut moved_idat = scoped_idat.clone();
|
||||||
*zm,
|
let moved_filtered = filtered.clone();
|
||||||
*zs,
|
scope.spawn(move || {
|
||||||
opts.window) {
|
let new_idat = match deflate::deflate::deflate(&moved_filtered,
|
||||||
Ok(x) => x,
|
*zc,
|
||||||
Err(x) => return Err(x),
|
*zm,
|
||||||
};
|
*zs,
|
||||||
if new_idat.len() < png.idat_data.len() ||
|
opts.window) {
|
||||||
(best.is_none() && something_changed) {
|
Ok(x) => x,
|
||||||
best = Some((*f, *zc, *zm, *zs));
|
Err(x) => return Err(x),
|
||||||
png.idat_data = new_idat.clone();
|
};
|
||||||
}
|
if new_idat.len() < moved_png.idat_data.len() ||
|
||||||
if opts.verbosity == Some(1) {
|
(best.is_none() && something_changed) {
|
||||||
println!(" zc = {} zm = {} zs = {} f = {} {} bytes",
|
best = Some((*f, *zc, *zm, *zs));
|
||||||
*zc,
|
*Arc::make_mut(&mut moved_idat) = new_idat.clone();
|
||||||
*zm,
|
}
|
||||||
*zs,
|
if opts.verbosity == Some(1) {
|
||||||
*f,
|
println!(" zc = {} zm = {} zs = {} f = {} {} bytes",
|
||||||
new_idat.len());
|
*zc,
|
||||||
|
*zm,
|
||||||
|
*zs,
|
||||||
|
*f,
|
||||||
|
new_idat.len());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if let Some(better) = best {
|
if let Some(better) = best {
|
||||||
|
png.idat_data = Arc::try_unwrap(scoped_idat).unwrap().clone();
|
||||||
println!("Found better combination:");
|
println!("Found better combination:");
|
||||||
println!(" zc = {} zm = {} zs = {} f = {} {} bytes",
|
println!(" zc = {} zm = {} zs = {} f = {} {} bytes",
|
||||||
better.1,
|
better.1,
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ struct ScanLine {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug,Clone)]
|
||||||
pub struct PngData {
|
pub struct PngData {
|
||||||
pub idat_data: Vec<u8>,
|
pub idat_data: Vec<u8>,
|
||||||
pub ihdr_data: IhdrData,
|
pub ihdr_data: IhdrData,
|
||||||
|
|
@ -134,7 +134,7 @@ pub struct PngData {
|
||||||
pub aux_headers: HashMap<String, Vec<u8>>,
|
pub aux_headers: HashMap<String, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug,Clone)]
|
||||||
pub struct IhdrData {
|
pub struct IhdrData {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
|
|
|
||||||
|
|
@ -371,7 +371,7 @@ fn palette_should_be_grayscale() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn strip_headers() {
|
fn strip_headers() {
|
||||||
let input = PathBuf::from("tests/files/rgb_should_be_palette.png");
|
let input = PathBuf::from("tests/files/rgb_should_be_rgb.png");
|
||||||
let mut opts = get_opts(&input);
|
let mut opts = get_opts(&input);
|
||||||
opts.strip = true;
|
opts.strip = true;
|
||||||
let output = opts.out_file.clone();
|
let output = opts.out_file.clone();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue