Use deflater on iCCP chunk as well
This commit is contained in:
parent
d1a78f97bf
commit
a330187a51
3 changed files with 22 additions and 24 deletions
|
|
@ -107,23 +107,26 @@ impl Deflater for BufferedZopfliDeflater {
|
||||||
maximum_block_splits: self.max_block_splits,
|
maximum_block_splits: self.max_block_splits,
|
||||||
..Default::default() // for forward compatibility
|
..Default::default() // for forward compatibility
|
||||||
};
|
};
|
||||||
|
let mut out = Vec::with_capacity(self.output_buffer_size);
|
||||||
let mut buffer = BufWriter::with_capacity(
|
let mut buffer = BufWriter::with_capacity(
|
||||||
self.input_buffer_size,
|
self.input_buffer_size,
|
||||||
DeflateEncoder::new(
|
DeflateEncoder::new(
|
||||||
options,
|
options,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
Cursor::new(Vec::with_capacity(self.output_buffer_size)),
|
&mut out,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
let result = (|| -> io::Result<Vec<u8>> {
|
let result = (|| -> io::Result<()> {
|
||||||
buffer.write_all(data)?;
|
buffer.write_all(data)?;
|
||||||
Ok(buffer.into_inner()?.finish()?.into_inner())
|
buffer.into_inner()?.finish()?;
|
||||||
|
Ok(())
|
||||||
})();
|
})();
|
||||||
let result = result.map_err(|e| PngError::new(&e.to_string()))?;
|
result.map_err(|e| PngError::new(&e.to_string()))?;
|
||||||
if max_size.get().is_some_and(|max| max < result.len()) {
|
println!("Compressed {} -> {} bytes", data.len(), out.len());
|
||||||
Err(PngError::DeflatedDataTooLong(result.len()))
|
if max_size.get().is_some_and(|max| max < out.len()) {
|
||||||
|
Err(PngError::DeflatedDataTooLong(out.len()))
|
||||||
} else {
|
} else {
|
||||||
Ok(result)
|
Ok(out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
src/lib.rs
17
src/lib.rs
|
|
@ -403,7 +403,7 @@ impl RawImage {
|
||||||
.filter(|c| opts.strip.keep(&c.name))
|
.filter(|c| opts.strip.keep(&c.name))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
postprocess_chunks(&mut png, opts, &self.png.ihdr);
|
postprocess_chunks(&mut png, opts, &self.png.ihdr, deflater);
|
||||||
|
|
||||||
Ok(png.output())
|
Ok(png.output())
|
||||||
}
|
}
|
||||||
|
|
@ -579,7 +579,7 @@ fn optimize_png(
|
||||||
png.idat_data = new_png.idat_data;
|
png.idat_data = new_png.idat_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
postprocess_chunks(png, opts, &raw.ihdr);
|
postprocess_chunks(png, opts, &raw.ihdr, &opts.deflate);
|
||||||
|
|
||||||
let output = png.output();
|
let output = png.output();
|
||||||
|
|
||||||
|
|
@ -675,17 +675,9 @@ fn optimize_raw<T: Deflater>(
|
||||||
// We should have a result here - fail if not (e.g. deadline passed)
|
// We should have a result here - fail if not (e.g. deadline passed)
|
||||||
let result = eval_result?;
|
let result = eval_result?;
|
||||||
|
|
||||||
match opts.deflate {
|
|
||||||
Deflaters::Libdeflater { compression } if compression <= eval_compression => {
|
|
||||||
// No further compression required
|
|
||||||
Some((result.filter, result.idat_data))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
debug!("Trying: {}", result.filter);
|
debug!("Trying: {}", result.filter);
|
||||||
let best_size = AtomicMin::new(max_size);
|
let best_size = AtomicMin::new(max_size);
|
||||||
perform_trial(&result.filtered, opts, result.filter, &best_size, deflater)
|
perform_trial(&result.filtered, opts, result.filter, &best_size, deflater)
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Perform full compression trials of selected filters and determine the best
|
// Perform full compression trials of selected filters and determine the best
|
||||||
|
|
||||||
|
|
@ -855,7 +847,8 @@ fn report_format(prefix: &str, png: &PngImage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform cleanup of certain chunks from the `PngData` object, after optimization has been completed
|
/// 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<T>(png: &mut PngData, opts: &Options, orig_ihdr: &IhdrData, deflater: &T)
|
||||||
|
where T: Deflater {
|
||||||
if let Some(iccp_idx) = png.aux_chunks.iter().position(|c| &c.name == b"iCCP") {
|
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
|
// 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");
|
let may_replace_iccp = opts.strip != StripChunks::None && opts.strip.keep(b"sRGB");
|
||||||
|
|
@ -877,7 +870,7 @@ fn postprocess_chunks(png: &mut PngData, opts: &Options, orig_ihdr: &IhdrData) {
|
||||||
name: *b"sRGB",
|
name: *b"sRGB",
|
||||||
data: vec![intent],
|
data: vec![intent],
|
||||||
};
|
};
|
||||||
} else if let Ok(iccp) = construct_iccp(&icc, &opts.deflate) {
|
} else if let Ok(iccp) = construct_iccp(&icc, deflater) {
|
||||||
let cur_len = png.aux_chunks[iccp_idx].data.len();
|
let cur_len = png.aux_chunks[iccp_idx].data.len();
|
||||||
let new_len = iccp.data.len();
|
let new_len = iccp.data.len();
|
||||||
if new_len < cur_len {
|
if new_len < cur_len {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ fn get_opts() -> Options {
|
||||||
fn test_it_converts(input: &str) {
|
fn test_it_converts(input: &str) {
|
||||||
let input = PathBuf::from(input);
|
let input = PathBuf::from(input);
|
||||||
let opts = get_opts();
|
let opts = get_opts();
|
||||||
|
let deflater = BufferedZopfliDeflater::default();
|
||||||
|
|
||||||
let original_data = PngData::read_file(&PathBuf::from(input)).unwrap();
|
let original_data = PngData::read_file(&PathBuf::from(input)).unwrap();
|
||||||
let image = PngData::from_slice(&original_data, &opts).unwrap();
|
let image = PngData::from_slice(&original_data, &opts).unwrap();
|
||||||
|
|
@ -35,7 +36,7 @@ fn test_it_converts(input: &str) {
|
||||||
raw.add_png_chunk(chunk.name, chunk.data);
|
raw.add_png_chunk(chunk.name, chunk.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = raw.create_optimized_png(&opts).unwrap();
|
let output = raw.create_optimized_png(&opts, &deflater).unwrap();
|
||||||
|
|
||||||
let new = PngData::from_slice(&output, &opts).unwrap();
|
let new = PngData::from_slice(&output, &opts).unwrap();
|
||||||
assert!(new.aux_chunks.len() == num_chunks);
|
assert!(new.aux_chunks.len() == num_chunks);
|
||||||
|
|
@ -52,6 +53,7 @@ fn from_file() {
|
||||||
#[test]
|
#[test]
|
||||||
fn custom_indexed() {
|
fn custom_indexed() {
|
||||||
let opts = get_opts();
|
let opts = get_opts();
|
||||||
|
let deflater = BufferedZopfliDeflater::default();
|
||||||
|
|
||||||
let raw = RawImage::new(
|
let raw = RawImage::new(
|
||||||
4,
|
4,
|
||||||
|
|
@ -69,7 +71,7 @@ fn custom_indexed() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
raw.create_optimized_png(&opts).unwrap();
|
raw.create_optimized_png(&opts, &deflater).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue