Eliminate many clones
This commit is contained in:
parent
9d018a3f3b
commit
dbc3d97513
6 changed files with 37 additions and 37 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
- [SEMVER_MAJOR] Bump minimum rustc version to 1.9.0, required by dependencies
|
- [SEMVER_MAJOR] Bump minimum rustc version to 1.9.0, required by dependencies
|
||||||
- [SEMVER_MINOR] Allow calling optimization presets via crate using `Options::from_preset`
|
- [SEMVER_MINOR] Allow calling optimization presets via crate using `Options::from_preset`
|
||||||
- [SEMVER_MAJOR] Return proper `PngError` type which implements `std::error::Error` from `Result`s
|
- [SEMVER_MAJOR] Return proper `PngError` type which implements `std::error::Error` from `Result`s
|
||||||
|
- Performance optimizations
|
||||||
|
|
||||||
**Version 0.10.0**
|
**Version 0.10.0**
|
||||||
- [SEMVER_MINOR] Make clap and regex dependencies optional
|
- [SEMVER_MINOR] Make clap and regex dependencies optional
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ pub fn parse_next_header(byte_data: &[u8],
|
||||||
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
||||||
};
|
};
|
||||||
*byte_offset += 4;
|
*byte_offset += 4;
|
||||||
header_bytes.extend(data.clone());
|
header_bytes.extend_from_slice(&data);
|
||||||
if !fix_errors && crc32::checksum_ieee(header_bytes.as_ref()) != crc {
|
if !fix_errors && crc32::checksum_ieee(header_bytes.as_ref()) != crc {
|
||||||
return Err(PngError::new(&format!("CRC Mismatch in {} header; May be recoverable by using --fix",
|
return Err(PngError::new(&format!("CRC Mismatch in {} header; May be recoverable by using --fix",
|
||||||
header)));
|
header)));
|
||||||
|
|
|
||||||
49
src/lib.rs
49
src/lib.rs
|
|
@ -15,7 +15,7 @@ use std::collections::{HashMap, HashSet};
|
||||||
use std::fs::{File, copy};
|
use std::fs::{File, copy};
|
||||||
use std::io::{BufWriter, Write, stderr, stdout};
|
use std::io::{BufWriter, Write, stderr, stdout};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Mutex;
|
||||||
|
|
||||||
pub mod colors;
|
pub mod colors;
|
||||||
pub mod deflate {
|
pub mod deflate {
|
||||||
|
|
@ -425,7 +425,7 @@ fn optimize_png(mut png: &mut png::PngData, file_original_size: usize, opts: &Op
|
||||||
png.ihdr_data.width,
|
png.ihdr_data.width,
|
||||||
png.ihdr_data.height)
|
png.ihdr_data.height)
|
||||||
.ok();
|
.ok();
|
||||||
if let Some(palette) = png.palette.clone() {
|
if let Some(ref palette) = png.palette {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
" {} bits/pixel, {} colors in palette",
|
" {} bits/pixel, {} colors in palette",
|
||||||
png.ihdr_data.bit_depth,
|
png.ihdr_data.bit_depth,
|
||||||
|
|
@ -450,8 +450,8 @@ fn optimize_png(mut png: &mut png::PngData, file_original_size: usize, opts: &Op
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut filter = opts.filter.clone();
|
let mut filter = opts.filter.clone();
|
||||||
let compression = opts.compression.clone();
|
let compression = &opts.compression;
|
||||||
let memory = opts.memory.clone();
|
let memory = &opts.memory;
|
||||||
let mut strategies = opts.strategies.clone();
|
let mut strategies = opts.strategies.clone();
|
||||||
|
|
||||||
if opts.use_heuristics {
|
if opts.use_heuristics {
|
||||||
|
|
@ -480,21 +480,21 @@ fn optimize_png(mut png: &mut png::PngData, file_original_size: usize, opts: &Op
|
||||||
let thread_count = opts.threads;
|
let thread_count = opts.threads;
|
||||||
let pool = Pool::new(thread_count);
|
let pool = Pool::new(thread_count);
|
||||||
// Go through selected permutations and determine the best
|
// Go through selected permutations and determine the best
|
||||||
let best: Arc<Mutex<Option<TrialWithData>>> = Arc::new(Mutex::new(None));
|
let best: Mutex<Option<TrialWithData>> = Mutex::new(None);
|
||||||
let combinations = filter.len() * compression.len() * memory.len() * strategies.len();
|
let combinations = filter.len() * compression.len() * memory.len() * strategies.len();
|
||||||
let mut results: Vec<(u8, u8, u8, u8)> = Vec::with_capacity(combinations);
|
let mut results: Vec<(u8, u8, u8, u8)> = Vec::with_capacity(combinations);
|
||||||
let filters: Arc<Mutex<HashMap<u8, Vec<u8>>>> =
|
let filters: Mutex<HashMap<u8, Vec<u8>>> =
|
||||||
Arc::new(Mutex::new(HashMap::with_capacity(filter.len())));
|
Mutex::new(HashMap::with_capacity(filter.len()));
|
||||||
if opts.verbosity.is_some() {
|
if opts.verbosity.is_some() {
|
||||||
writeln!(&mut stderr(), "Trying: {} combinations", combinations).ok();
|
writeln!(&mut stderr(), "Trying: {} combinations", combinations).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.scoped(|scope| {
|
pool.scoped(|scope| {
|
||||||
for f in &filter {
|
for f in &filter {
|
||||||
let png = png.clone();
|
let png = &png;
|
||||||
let filters = filters.clone();
|
let filters = &filters;
|
||||||
for zc in &compression {
|
for zc in compression {
|
||||||
for zm in &memory {
|
for zm in memory {
|
||||||
for zs in &strategies {
|
for zs in &strategies {
|
||||||
results.push((*f, *zc, *zm, *zs));
|
results.push((*f, *zc, *zm, *zs));
|
||||||
}
|
}
|
||||||
|
|
@ -516,7 +516,7 @@ fn optimize_png(mut png: &mut png::PngData, file_original_size: usize, opts: &Op
|
||||||
opts.interlace != Some(png.ihdr_data.interlaced);
|
opts.interlace != Some(png.ihdr_data.interlaced);
|
||||||
for trial in &results {
|
for trial in &results {
|
||||||
let filtered = filters.get(&trial.0).unwrap();
|
let filtered = filters.get(&trial.0).unwrap();
|
||||||
let best = best.clone();
|
let best = &best;
|
||||||
scope.execute(move || {
|
scope.execute(move || {
|
||||||
let new_idat =
|
let new_idat =
|
||||||
deflate::deflate::deflate(filtered, trial.1, trial.2, trial.3, opts.window)
|
deflate::deflate::deflate(filtered, trial.1, trial.2, trial.3, opts.window)
|
||||||
|
|
@ -546,7 +546,7 @@ fn optimize_png(mut png: &mut png::PngData, file_original_size: usize, opts: &Op
|
||||||
|
|
||||||
let mut final_best = best.lock().unwrap();
|
let mut final_best = best.lock().unwrap();
|
||||||
if let Some(better) = final_best.take() {
|
if let Some(better) = final_best.take() {
|
||||||
png.idat_data = better.4.clone();
|
png.idat_data = better.4;
|
||||||
if opts.verbosity.is_some() {
|
if opts.verbosity.is_some() {
|
||||||
writeln!(&mut stderr(), "Found better combination:").ok();
|
writeln!(&mut stderr(), "Found better combination:").ok();
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
|
|
@ -650,7 +650,7 @@ fn perform_reductions(png: &mut png::PngData, opts: &Options) -> bool {
|
||||||
/// Display the status of the image data after a reduction has taken place
|
/// Display the status of the image data after a reduction has taken place
|
||||||
#[inline]
|
#[inline]
|
||||||
fn report_reduction(png: &png::PngData) {
|
fn report_reduction(png: &png::PngData) {
|
||||||
if let Some(palette) = png.palette.clone() {
|
if let Some(ref palette) = png.palette {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
"Reducing image to {} bits/pixel, {} colors in palette",
|
"Reducing image to {} bits/pixel, {} colors in palette",
|
||||||
png.ihdr_data.bit_depth,
|
png.ihdr_data.bit_depth,
|
||||||
|
|
@ -668,26 +668,25 @@ fn report_reduction(png: &png::PngData) {
|
||||||
|
|
||||||
/// Strip headers from the `PngData` object, as requested by the passed `Options`
|
/// Strip headers from the `PngData` object, as requested by the passed `Options`
|
||||||
fn perform_strip(png: &mut png::PngData, opts: &Options) {
|
fn perform_strip(png: &mut png::PngData, opts: &Options) {
|
||||||
match opts.strip.clone() {
|
match &opts.strip {
|
||||||
// Strip headers
|
// Strip headers
|
||||||
Headers::None => (),
|
&Headers::None => (),
|
||||||
Headers::Some(hdrs) => {
|
&Headers::Some(ref hdrs) => {
|
||||||
for hdr in &hdrs {
|
for hdr in hdrs {
|
||||||
png.aux_headers.remove(hdr);
|
png.aux_headers.remove(hdr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Headers::Safe => {
|
&Headers::Safe => {
|
||||||
const PRESERVED_HEADERS: [&'static str; 9] = ["cHRM", "gAMA", "iCCP", "sBIT", "sRGB",
|
const PRESERVED_HEADERS: [&'static str; 9] = ["cHRM", "gAMA", "iCCP", "sBIT", "sRGB",
|
||||||
"bKGD", "hIST", "pHYs", "sPLT"];
|
"bKGD", "hIST", "pHYs", "sPLT"];
|
||||||
let mut preserved = HashMap::new();
|
let hdrs = png.aux_headers.keys().cloned().collect::<Vec<String>>();
|
||||||
for (hdr, contents) in &png.aux_headers {
|
for hdr in hdrs {
|
||||||
if PRESERVED_HEADERS.contains(&hdr.as_ref()) {
|
if !PRESERVED_HEADERS.contains(&hdr.as_ref()) {
|
||||||
preserved.insert(hdr.clone(), contents.clone());
|
png.aux_headers.remove(&hdr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
png.aux_headers = preserved;
|
|
||||||
}
|
}
|
||||||
Headers::All => {
|
&Headers::All => {
|
||||||
png.aux_headers = HashMap::new();
|
png.aux_headers = HashMap::new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ fn handle_optimization(inputs: Vec<PathBuf>, opts: Options) {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(out_dir) = current_opts.out_dir.clone() {
|
if let Some(ref out_dir) = current_opts.out_dir {
|
||||||
current_opts.out_file = out_dir.join(input.file_name().unwrap());
|
current_opts.out_file = out_dir.join(input.file_name().unwrap());
|
||||||
} else if current_opts.out_file.components().count() == 0 {
|
} else if current_opts.out_file.components().count() == 0 {
|
||||||
current_opts.out_file = input.clone();
|
current_opts.out_file = input.clone();
|
||||||
|
|
|
||||||
10
src/png.rs
10
src/png.rs
|
|
@ -251,7 +251,7 @@ impl PngData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut png_data = PngData {
|
let mut png_data = PngData {
|
||||||
idat_data: idat_headers.clone(),
|
idat_data: idat_headers,
|
||||||
ihdr_data: ihdr_header,
|
ihdr_data: ihdr_header,
|
||||||
raw_data: raw_data,
|
raw_data: raw_data,
|
||||||
palette: aux_headers.remove("PLTE"),
|
palette: aux_headers.remove("PLTE"),
|
||||||
|
|
@ -304,13 +304,13 @@ impl PngData {
|
||||||
write_png_block(key.as_bytes(), header, &mut output);
|
write_png_block(key.as_bytes(), header, &mut output);
|
||||||
}
|
}
|
||||||
// Palette
|
// Palette
|
||||||
if let Some(palette) = self.palette.clone() {
|
if let Some(ref palette) = self.palette {
|
||||||
write_png_block(b"PLTE", &palette, &mut output);
|
write_png_block(b"PLTE", &palette, &mut output);
|
||||||
if let Some(transparency_palette) = self.transparency_palette.clone() {
|
if let Some(ref transparency_palette) = self.transparency_palette {
|
||||||
// Transparency pixel
|
// Transparency pixel
|
||||||
write_png_block(b"tRNS", &transparency_palette, &mut output);
|
write_png_block(b"tRNS", &transparency_palette, &mut output);
|
||||||
}
|
}
|
||||||
} else if let Some(transparency_pixel) = self.transparency_pixel.clone() {
|
} else if let Some(ref transparency_pixel) = self.transparency_pixel {
|
||||||
// Transparency pixel
|
// Transparency pixel
|
||||||
write_png_block(b"tRNS", &transparency_pixel, &mut output);
|
write_png_block(b"tRNS", &transparency_pixel, &mut output);
|
||||||
}
|
}
|
||||||
|
|
@ -405,7 +405,7 @@ impl PngData {
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
last_line = line.data.clone();
|
last_line = line.data;
|
||||||
last_pass = line.pass;
|
last_pass = line.pass;
|
||||||
}
|
}
|
||||||
filtered
|
filtered
|
||||||
|
|
|
||||||
|
|
@ -123,10 +123,10 @@ pub fn reduce_rgba_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>, Vec<u8
|
||||||
if len == 256 {
|
if len == 256 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
palette.push(cur_pixel.clone());
|
palette.push(cur_pixel);
|
||||||
reduced.push(len as u8);
|
reduced.push(len as u8);
|
||||||
}
|
}
|
||||||
cur_pixel.clear();
|
cur_pixel = Vec::with_capacity(bpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,10 +166,10 @@ pub fn reduce_rgb_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>)> {
|
||||||
if len == 256 {
|
if len == 256 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
palette.push(cur_pixel.clone());
|
palette.push(cur_pixel);
|
||||||
reduced.push(len as u8);
|
reduced.push(len as u8);
|
||||||
}
|
}
|
||||||
cur_pixel.clear();
|
cur_pixel = Vec::with_capacity(bpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -211,7 +211,7 @@ pub fn reduce_grayscale_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>)>
|
||||||
if len == 16 {
|
if len == 16 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
palette.push(pix_slice.clone());
|
palette.push(pix_slice);
|
||||||
let idx = BitVec::from_bytes(&[(len as u8) << bpp_inverse]);
|
let idx = BitVec::from_bytes(&[(len as u8) << bpp_inverse]);
|
||||||
for b in idx.iter().take(bpp) {
|
for b in idx.iter().take(bpp) {
|
||||||
reduced.push(b);
|
reduced.push(b);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue