Return candidate from optimize_raw

This commit is contained in:
Andrew 2025-01-22 20:58:38 +13:00
parent 78b9bd47d0
commit d8da0b2423
2 changed files with 26 additions and 31 deletions

View file

@ -156,16 +156,21 @@ impl RawImage {
/// Create an optimized png from the raw image data using the options provided /// Create an optimized png from the raw image data using the options provided
pub fn create_optimized_png(&self, opts: &Options) -> PngResult<Vec<u8>> { pub fn create_optimized_png(&self, opts: &Options) -> PngResult<Vec<u8>> {
let deadline = Arc::new(Deadline::new(opts.timeout)); let deadline = Arc::new(Deadline::new(opts.timeout));
let mut png = optimize_raw(self.png.clone(), opts, deadline.clone(), None) let Some(result) = optimize_raw(self.png.clone(), opts, deadline, None) else {
.ok_or_else(|| PngError::new("Failed to optimize input data"))?; return Err(PngError::new("Failed to optimize input data"));
};
// Process aux chunks let mut png = PngData {
png.aux_chunks = self raw: result.image,
.aux_chunks idat_data: result.idat_data,
.iter() aux_chunks: self
.filter(|c| opts.strip.keep(&c.name)) .aux_chunks
.cloned() .iter()
.collect(); .filter(|c| opts.strip.keep(&c.name))
.cloned()
.collect(),
frames: Vec::new(),
};
postprocess_chunks(&mut png, opts, &self.png.ihdr); postprocess_chunks(&mut png, opts, &self.png.ihdr);
Ok(png.output()) Ok(png.output())
@ -359,14 +364,13 @@ fn optimize_png(
} else { } else {
Some(png.estimated_output_size()) Some(png.estimated_output_size())
}; };
if let Some(new_png) = optimize_raw(raw.clone(), &opts, deadline.clone(), max_size) { if let Some(result) = optimize_raw(raw.clone(), &opts, deadline.clone(), max_size) {
png.raw = new_png.raw; png.raw = result.image;
png.idat_data = new_png.idat_data; png.idat_data = result.idat_data;
png.filter = new_png.filter; recompress_frames(png, &opts, deadline, result.filter)?;
} }
postprocess_chunks(png, &opts, &raw.ihdr); postprocess_chunks(png, &opts, &raw.ihdr);
recompress_frames(png, &opts, deadline)?;
let output = png.output(); let output = png.output();
@ -415,7 +419,7 @@ fn optimize_raw(
opts: &Options, opts: &Options,
deadline: Arc<Deadline>, deadline: Arc<Deadline>,
max_size: Option<usize>, max_size: Option<usize>,
) -> Option<PngData> { ) -> Option<Candidate> {
// Libdeflate has four algorithms: 0 = 'uncompressed', 1-4 = 'greedy', 5-7 = 'lazy', 8-9 = 'lazy2', 10-12 = 'near-optimal' // Libdeflate has four algorithms: 0 = 'uncompressed', 1-4 = 'greedy', 5-7 = 'lazy', 8-9 = 'lazy2', 10-12 = 'near-optimal'
// 5 is the minimumm required for a decent evaluation result // 5 is the minimumm required for a decent evaluation result
// 7 is not noticeably slower than 5 and improves evaluation of filters in 'fast' mode (o2 and lower) // 7 is not noticeably slower than 5 and improves evaluation of filters in 'fast' mode (o2 and lower)
@ -471,13 +475,7 @@ fn optimize_raw(
if max_size.map_or(true, |max_size| result.estimated_output_size() < max_size) { if max_size.map_or(true, |max_size| result.estimated_output_size() < max_size) {
debug!("Found better result:"); debug!("Found better result:");
debug!(" zc = {} f = {}", deflater, result.filter); debug!(" zc = {} f = {}", deflater, result.filter);
return Some(PngData { return Some(result);
raw: result.image,
idat_data: result.idat_data,
aux_chunks: Vec::new(),
frames: Vec::new(),
filter: Some(result.filter),
});
} }
None None
} }
@ -677,15 +675,15 @@ fn postprocess_chunks(png: &mut PngData, opts: &Options, orig_ihdr: &IhdrData) {
} }
/// Recompress the additional frames of an APNG /// Recompress the additional frames of an APNG
fn recompress_frames(png: &mut PngData, opts: &Options, deadline: Arc<Deadline>) -> PngResult<()> { fn recompress_frames(
png: &mut PngData,
opts: &Options,
deadline: Arc<Deadline>,
filter: RowFilter,
) -> PngResult<()> {
if !opts.idat_recoding || png.frames.is_empty() { if !opts.idat_recoding || png.frames.is_empty() {
return Ok(()); return Ok(());
} }
// Use the same filter chosen for the main image
// No filter means we failed to optimise the main image and we shouldn't bother trying here
let Some(filter) = png.filter else {
return Ok(());
};
png.frames png.frames
.par_iter_mut() .par_iter_mut()
.with_max_len(1) .with_max_len(1)

View file

@ -50,8 +50,6 @@ pub struct PngData {
pub aux_chunks: Vec<Chunk>, pub aux_chunks: Vec<Chunk>,
/// APNG frames /// APNG frames
pub frames: Vec<Frame>, pub frames: Vec<Frame>,
/// The filter strategy applied to the idat_data (initially unknown)
pub filter: Option<RowFilter>,
} }
impl PngData { impl PngData {
@ -184,7 +182,6 @@ impl PngData {
raw: Arc::new(raw), raw: Arc::new(raw),
aux_chunks, aux_chunks,
frames, frames,
filter: None,
}) })
} }