Minor compression improvement in interlaced images
This commit is contained in:
parent
15e41c9c6d
commit
c0fddfe4e6
2 changed files with 39 additions and 28 deletions
|
|
@ -1,3 +1,6 @@
|
||||||
|
**Version 0.6.1 (unreleased)**
|
||||||
|
- Minor compression improvement on interlaced images
|
||||||
|
|
||||||
**Version 0.6.0**
|
**Version 0.6.0**
|
||||||
- Fix issue where output directory would not be created if it did not exist
|
- Fix issue where output directory would not be created if it did not exist
|
||||||
- Use miniz for compression strategies where it outperforms zlib
|
- Use miniz for compression strategies where it outperforms zlib
|
||||||
|
|
|
||||||
64
src/png.rs
64
src/png.rs
|
|
@ -466,37 +466,45 @@ impl PngData {
|
||||||
let mut last_line: Vec<u8> = Vec::new();
|
let mut last_line: Vec<u8> = Vec::new();
|
||||||
let mut last_pass: Option<u8> = None;
|
let mut last_pass: Option<u8> = None;
|
||||||
for line in self.scan_lines() {
|
for line in self.scan_lines() {
|
||||||
if last_pass == line.pass {
|
match filter {
|
||||||
match filter {
|
0 | 1 | 2 | 3 | 4 => {
|
||||||
0 | 1 | 2 | 3 | 4 => {
|
if last_pass == line.pass || filter <= 1 {
|
||||||
filtered.push(filter);
|
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 {
|
5 => {
|
||||||
filtered.push(0);
|
// Heuristically guess best filter per line
|
||||||
filtered.extend(filter_line(0, bpp, &line.data, &last_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_line = line.data.clone();
|
||||||
last_pass = line.pass;
|
last_pass = line.pass;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue