Remove filtered from PngData
This commit is contained in:
parent
4a1cd2db3e
commit
526429a522
3 changed files with 45 additions and 46 deletions
|
|
@ -4,7 +4,6 @@
|
|||
use crate::atomicmin::AtomicMin;
|
||||
use crate::deflate;
|
||||
use crate::filters::RowFilter;
|
||||
use crate::png::PngData;
|
||||
use crate::png::PngImage;
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
use crate::rayon;
|
||||
|
|
@ -22,7 +21,9 @@ use std::sync::atomic::Ordering::SeqCst;
|
|||
use std::sync::Arc;
|
||||
|
||||
pub struct Candidate {
|
||||
pub image: PngData,
|
||||
pub image: Arc<PngImage>,
|
||||
pub idat_data: Vec<u8>,
|
||||
pub filtered: Vec<u8>,
|
||||
pub filter: RowFilter,
|
||||
pub is_reduction: bool,
|
||||
// first wins tie-breaker
|
||||
|
|
@ -32,9 +33,9 @@ pub struct Candidate {
|
|||
impl Candidate {
|
||||
fn cmp_key(&self) -> impl Ord {
|
||||
(
|
||||
self.image.estimated_output_size(),
|
||||
self.image.raw.data.len(),
|
||||
self.image.raw.ihdr.bit_depth,
|
||||
self.idat_data.len() + self.image.key_chunks_size(),
|
||||
self.image.data.len(),
|
||||
self.image.ihdr.bit_depth,
|
||||
self.filter,
|
||||
self.nth,
|
||||
)
|
||||
|
|
@ -135,18 +136,7 @@ impl Evaluator {
|
|||
let filtered = image.filter_image(filter, optimize_alpha);
|
||||
let idat_data = deflate::deflate(&filtered, compression, &best_candidate_size);
|
||||
if let Ok(idat_data) = idat_data {
|
||||
let new = Candidate {
|
||||
image: PngData {
|
||||
idat_data,
|
||||
filtered,
|
||||
raw: Arc::clone(&image),
|
||||
aux_chunks: Vec::new(),
|
||||
},
|
||||
filter,
|
||||
is_reduction,
|
||||
nth,
|
||||
};
|
||||
let size = new.image.estimated_output_size();
|
||||
let size = idat_data.len() + image.key_chunks_size();
|
||||
best_candidate_size.set_min(size);
|
||||
trace!(
|
||||
"Eval: {}-bit {:20} {:8} {} bytes",
|
||||
|
|
@ -155,6 +145,14 @@ impl Evaluator {
|
|||
filter,
|
||||
size
|
||||
);
|
||||
let new = Candidate {
|
||||
image: image.clone(),
|
||||
idat_data,
|
||||
filtered,
|
||||
filter,
|
||||
is_reduction,
|
||||
nth,
|
||||
};
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
{
|
||||
|
|
|
|||
16
src/lib.rs
16
src/lib.rs
|
|
@ -632,7 +632,7 @@ fn optimize_raw(
|
|||
let mut eval_result = eval.get_best_candidate();
|
||||
if let Some(ref result) = eval_result {
|
||||
if result.is_reduction {
|
||||
png = Arc::clone(&result.image.raw);
|
||||
png = result.image.clone();
|
||||
reduction_occurred = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -656,7 +656,7 @@ fn optimize_raw(
|
|||
trace!("Evaluating: {} filters", filters.len());
|
||||
let eval = Evaluator::new(deadline, filters, eval_compression, opts.optimize_alpha);
|
||||
if let Some(ref result) = eval_result {
|
||||
eval.set_best_size(result.image.idat_data.len());
|
||||
eval.set_best_size(result.idat_data.len());
|
||||
}
|
||||
eval.try_image(png.clone());
|
||||
if let Some(result) = eval.get_best_candidate() {
|
||||
|
|
@ -669,12 +669,12 @@ fn optimize_raw(
|
|||
match opts.deflate {
|
||||
Deflaters::Libdeflater { compression } if compression <= eval_compression => {
|
||||
// No further compression required
|
||||
Some((result.filter, result.image.idat_data))
|
||||
Some((result.filter, result.idat_data))
|
||||
}
|
||||
_ => {
|
||||
debug!("Trying: {}", result.filter);
|
||||
let best_size = AtomicMin::new(max_size);
|
||||
perform_trial(&result.image.filtered, opts, result.filter, &best_size)
|
||||
perform_trial(&result.filtered, opts, result.filter, &best_size)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -714,8 +714,6 @@ fn optimize_raw(
|
|||
if let Some((filter, idat_data)) = best {
|
||||
let image = PngData {
|
||||
raw: png,
|
||||
// The filtered data has not been retained here, but we don't need to return it
|
||||
filtered: Vec::new(),
|
||||
idat_data,
|
||||
aux_chunks: Vec::new(),
|
||||
};
|
||||
|
|
@ -733,7 +731,11 @@ fn optimize_raw(
|
|||
} else if let Some(result) = eval_result {
|
||||
// If idat_recoding is off and reductions were attempted but ended up choosing the baseline,
|
||||
// we should still check if the evaluator compressed the baseline smaller than the original.
|
||||
let image = result.image;
|
||||
let image = PngData {
|
||||
raw: result.image,
|
||||
idat_data: result.idat_data,
|
||||
aux_chunks: Vec::new(),
|
||||
};
|
||||
if image.estimated_output_size() < max_size.unwrap_or(usize::MAX) {
|
||||
debug!("Found better combination:");
|
||||
debug!(
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@ pub struct PngData {
|
|||
pub raw: Arc<PngImage>,
|
||||
/// The filtered and compressed data of the IDAT chunk
|
||||
pub idat_data: Vec<u8>,
|
||||
/// The filtered, uncompressed data of the IDAT chunk
|
||||
pub filtered: Vec<u8>,
|
||||
/// All non-critical chunks from the PNG are stored here
|
||||
pub aux_chunks: Vec<Chunk>,
|
||||
}
|
||||
|
|
@ -135,35 +133,18 @@ impl PngData {
|
|||
ihdr,
|
||||
data: raw_data,
|
||||
};
|
||||
let unfiltered = raw.unfilter_image()?;
|
||||
raw.data = raw.unfilter_image()?;
|
||||
// Return the PngData
|
||||
Ok(Self {
|
||||
idat_data,
|
||||
filtered: std::mem::replace(&mut raw.data, unfiltered),
|
||||
raw: Arc::new(raw),
|
||||
aux_chunks,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return an estimate of the output size
|
||||
/// Return an estimate of the output size which can help with evaluation of very small data
|
||||
pub fn estimated_output_size(&self) -> usize {
|
||||
// Add the size of the PLTE and tRNS chunks to the compressed idat size
|
||||
// This can help with evaluation of very small data
|
||||
let size = self.idat_data.len();
|
||||
size + match &self.raw.ihdr.color_type {
|
||||
ColorType::Indexed { palette } => {
|
||||
let plte = 12 + palette.len() * 3;
|
||||
let trns = palette.iter().filter(|p| p.a != 255).count();
|
||||
if trns != 0 {
|
||||
plte + 12 + trns
|
||||
} else {
|
||||
plte
|
||||
}
|
||||
}
|
||||
ColorType::Grayscale { transparent_shade } if transparent_shade.is_some() => 12 + 2,
|
||||
ColorType::RGB { transparent_color } if transparent_color.is_some() => 12 + 6,
|
||||
_ => 0,
|
||||
}
|
||||
self.idat_data.len() + self.raw.key_chunks_size()
|
||||
}
|
||||
|
||||
/// Format the `PngData` struct into a valid PNG bytestream
|
||||
|
|
@ -274,6 +255,24 @@ impl PngImage {
|
|||
}
|
||||
}
|
||||
|
||||
/// Calculate the size of the PLTE and tRNS chunks
|
||||
pub fn key_chunks_size(&self) -> usize {
|
||||
match &self.ihdr.color_type {
|
||||
ColorType::Indexed { palette } => {
|
||||
let plte = 12 + palette.len() * 3;
|
||||
let trns = palette.iter().filter(|p| p.a != 255).count();
|
||||
if trns != 0 {
|
||||
plte + 12 + trns
|
||||
} else {
|
||||
plte
|
||||
}
|
||||
}
|
||||
ColorType::Grayscale { transparent_shade } if transparent_shade.is_some() => 12 + 2,
|
||||
ColorType::RGB { transparent_color } if transparent_color.is_some() => 12 + 6,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterator over the scanlines of the image
|
||||
#[inline]
|
||||
pub fn scan_lines(&self, has_filter: bool) -> ScanLines<'_> {
|
||||
|
|
|
|||
Loading…
Reference in a new issue