Skip to content

Commit

Permalink
Recompress fdATs
Browse files Browse the repository at this point in the history
  • Loading branch information
andrews05 authored and shssoichiro committed May 30, 2023
1 parent 30308bc commit 1fd7f09
Showing 1 changed file with 42 additions and 5 deletions.
47 changes: 42 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ impl RawImage {
/// Create an optimized png from the raw image data using the options provided
pub fn create_optimized_png(&self, opts: &Options) -> PngResult<Vec<u8>> {
let deadline = Arc::new(Deadline::new(opts.timeout));
let mut png = optimize_raw(self.png.clone(), opts, deadline, None)
let mut png = optimize_raw(self.png.clone(), opts, deadline.clone(), None)
.ok_or_else(|| PngError::new("Failed to optimize input data"))?;

// Process aux chunks
Expand All @@ -399,7 +399,7 @@ impl RawImage {
.filter(|c| opts.strip.keep(&c.name))
.cloned()
.collect();
postprocess_chunks(&mut png, opts, &self.png.ihdr);
postprocess_chunks(&mut png, opts, deadline, &self.png.ihdr);

Ok(png.output())
}
Expand Down Expand Up @@ -583,12 +583,12 @@ fn optimize_png(
} else {
Some(png.estimated_output_size())
};
if let Some(new_png) = optimize_raw(raw.clone(), &opts, deadline, max_size) {
if let Some(new_png) = optimize_raw(raw.clone(), &opts, deadline.clone(), max_size) {
png.raw = new_png.raw;
png.idat_data = new_png.idat_data;
}

postprocess_chunks(png, &opts, &raw.ihdr);
postprocess_chunks(png, &opts, deadline, &raw.ihdr);

let output = png.output();

Expand Down Expand Up @@ -860,7 +860,12 @@ fn report_format(prefix: &str, png: &PngImage) {
}

/// Perform cleanup of certain chunks from the `PngData` object, after optimization has been completed
fn postprocess_chunks(png: &mut PngData, opts: &Options, orig_ihdr: &IhdrData) {
fn postprocess_chunks(
png: &mut PngData,
opts: &Options,
deadline: Arc<Deadline>,
orig_ihdr: &IhdrData,
) {
if let Some(iccp_idx) = png.aux_chunks.iter().position(|c| &c.name == b"iCCP") {
// See if we can replace an iCCP chunk with an sRGB chunk
let may_replace_iccp = opts.strip != StripChunks::None && opts.strip.keep(b"sRGB");
Expand Down Expand Up @@ -913,6 +918,38 @@ fn postprocess_chunks(png: &mut PngData, opts: &Options, orig_ihdr: &IhdrData) {
!invalid
});
}

// Find fdAT chunks and attempt to recompress them
// Note if there are multiple fdATs per frame then decompression will fail and nothing will change
let mut fdat: Vec<_> = png
.aux_chunks
.iter_mut()
.filter(|c| &c.name == b"fdAT")
.collect();
if !fdat.is_empty() {
let buffer_size = orig_ihdr.raw_data_size();
fdat.par_iter_mut()
.with_max_len(1)
.enumerate()
.for_each(|(i, c)| {
if deadline.passed() || c.data.len() <= 4 {
return;
}
if let Ok(mut data) = deflate::inflate(&c.data[4..], buffer_size).and_then(|data| {
let max_size = AtomicMin::new(Some(c.data.len() - 5));
opts.deflate.deflate(&data, &max_size)
}) {
debug!(
"Recompressed fdAT #{:<2}: {} ({} bytes decrease)",
i,
c.data.len(),
c.data.len() - 4 - data.len()
);
c.data.truncate(4);
c.data.append(&mut data);
}
})
}
}

/// Check if an image was already optimized prior to oxipng's operations
Expand Down

0 comments on commit 1fd7f09

Please sign in to comment.