Minor compression improvement in interlaced images

This commit is contained in:
Joshua Holmer 2016-05-02 13:54:04 -04:00
parent 15e41c9c6d
commit c0fddfe4e6
2 changed files with 39 additions and 28 deletions

View file

@ -1,3 +1,6 @@
**Version 0.6.1 (unreleased)**
- Minor compression improvement on interlaced images
**Version 0.6.0**
- Fix issue where output directory would not be created if it did not exist
- Use miniz for compression strategies where it outperforms zlib

View file

@ -466,37 +466,45 @@ impl PngData {
let mut last_line: Vec<u8> = Vec::new();
let mut last_pass: Option<u8> = None;
for line in self.scan_lines() {
if last_pass == line.pass {
match filter {
0 | 1 | 2 | 3 | 4 => {
match filter {
0 | 1 | 2 | 3 | 4 => {
if last_pass == line.pass || filter <= 1 {
filtered.push(filter);
filtered.extend(filter_line(filter, bpp, &line.data, &last_line));
filtered.extend_from_slice(&filter_line(filter,
bpp,
&line.data,
&last_line));
} else {
// Avoid vertical filtering on first line of each interlacing pass
filtered.push(0);
filtered.extend_from_slice(&filter_line(0, bpp, &line.data, &last_line));
}
5 => {
// Heuristically guess best filter per line
// Uses MSAD algorithm mentioned in libpng reference docs
// http://www.libpng.org/pub/png/book/chapter09.html
let mut trials: HashMap<u8, Vec<u8>> = HashMap::with_capacity(5);
for filter in 0..5 {
trials.insert(filter, filter_line(filter, bpp, &line.data, &last_line));
}
let (best_filter, best_line) = trials.iter()
.min_by_key(|x| {
x.1.iter().fold(0u64, |acc, &x| {
let signed = x as i8;
acc +
(signed as i16).abs() as u64
})
})
.unwrap();
filtered.push(*best_filter);
filtered.extend_from_slice(best_line);
}
_ => unreachable!(),
}
} else {
filtered.push(0);
filtered.extend(filter_line(0, bpp, &line.data, &last_line));
5 => {
// Heuristically guess best filter per line
// Uses MSAD algorithm mentioned in libpng reference docs
// http://www.libpng.org/pub/png/book/chapter09.html
let mut trials: HashMap<u8, Vec<u8>> = HashMap::with_capacity(5);
// Avoid vertical filtering on first line of each interlacing pass
for filter in if last_pass == line.pass {
0..5
} else {
0..2
} {
trials.insert(filter, filter_line(filter, bpp, &line.data, &last_line));
}
let (best_filter, best_line) = trials.iter()
.min_by_key(|x| {
x.1.iter().fold(0u64, |acc, &x| {
let signed = x as i8;
acc + (signed as i16).abs() as u64
})
})
.unwrap();
filtered.push(*best_filter);
filtered.extend_from_slice(best_line);
}
_ => unreachable!(),
}
last_line = line.data.clone();
last_pass = line.pass;