From fa2c69071cf1b36c096b1d5d5f85e762fbc07441 Mon Sep 17 00:00:00 2001 From: andrews05 Date: Thu, 18 Dec 2025 12:22:36 +1300 Subject: [PATCH] Ensure evaluator returns no result when all candidates are too large (#754) There was a small crack in the fast evaluation logic where a phase 2 candidate's IDAT could be compressed below the best size from phase 1, but the estimated output size (which includes chunks like PLTE) was above. This candidate could end up getting returned from the evaluator if no other filter actually did compress better, and would then be used for the final compression even though the phase 1 candidate was actually better. The issue could potentially affect small, indexed images in `--fast` mode (o2 and below). Fixes #753. --- src/evaluate.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/evaluate.rs b/src/evaluate.rs index d5c38e85..b9c572b8 100644 --- a/src/evaluate.rs +++ b/src/evaluate.rs @@ -154,6 +154,19 @@ impl Evaluator { let idat_data = deflater.deflate(&filtered, best_candidate_size.get()); if let Ok(idat_data) = idat_data { let estimated_output_size = image.estimated_output_size(&idat_data); + trace!( + "Eval: {}-bit {:23} {:8} {} bytes", + image.ihdr.bit_depth, description, filter, estimated_output_size + ); + + // Skip if it exceeds best known size. (This is important to ensure + // the evaluator returns no result when all candidates are too large.) + if let Some(max) = best_candidate_size.get() { + if estimated_output_size > max { + return; + } + } + // We only need to retain the IDAT data in the final round let new = Candidate { image: image.clone(), @@ -164,10 +177,6 @@ impl Evaluator { nth, }; best_candidate_size.set_min(estimated_output_size); - trace!( - "Eval: {}-bit {:23} {:8} {} bytes", - image.ihdr.bit_depth, description, filter, estimated_output_size - ); #[cfg(feature = "parallel")] {