Fix bug where interlaced images with certain widths would fail to optimize

This commit is contained in:
Joshua Holmer 2016-05-13 22:11:45 -04:00
parent 1d39714b0f
commit ecc19ad5cd
4 changed files with 50 additions and 23 deletions

View file

@ -1,5 +1,6 @@
**Version 0.8.1 (unreleased)**
- Minor optimizations
- Fix issue where interlaced images with certain widths would fail to optimize
**Version 0.8.0**
- [SEMVER_MINOR] Add support for optimizing PNGs already loaded into memory via library function

View file

@ -151,58 +151,69 @@ impl<'a> Iterator for ScanLines<'a> {
pass.1 = 0;
}
}
let bits_per_pixel = self.png.ihdr_data.bit_depth.as_u8() as usize *
self.png.channels_per_pixel() as usize;
let mut bits_per_line = self.png.ihdr_data.width as usize * bits_per_pixel;
let bits_per_pixel = self.png.ihdr_data.bit_depth.as_u8() as u32 *
self.png.channels_per_pixel() as u32;
let y_steps;
let pixels_factor;
match self.pass {
Some((1, _)) | Some((2, _)) => {
bits_per_line = (bits_per_line as f32 / 8f32).ceil() as usize;
pixels_factor = 8;
y_steps = 8;
}
Some((3, _)) => {
bits_per_line = (bits_per_line as f32 / 4f32).ceil() as usize;
pixels_factor = 4;
y_steps = 8;
}
Some((4, _)) => {
bits_per_line = (bits_per_line as f32 / 4f32).ceil() as usize;
pixels_factor = 4;
y_steps = 4;
}
Some((5, _)) => {
bits_per_line = (bits_per_line as f32 / 2f32).ceil() as usize;
pixels_factor = 2;
y_steps = 4;
}
Some((6, _)) => {
bits_per_line = (bits_per_line as f32 / 2f32).ceil() as usize;
pixels_factor = 2;
y_steps = 2;
}
Some((7, _)) => {
pixels_factor = 1;
y_steps = 2;
}
_ => unreachable!(),
}
// Determine whether to trim the last (overflow) pixel for rows on this pass
let gap = bits_per_line % bits_per_pixel;
if gap != 0 {
let x_start = bits_per_pixel *
match self.pass.unwrap().0 {
2 => 4,
4 => 2,
6 => 1,
_ => 0,
let mut pixels_per_line = self.png.ihdr_data.width / pixels_factor as u32;
// Determine whether to add pixels if there is a final, incomplete 8x8 block
let gap = self.png.ihdr_data.width % pixels_factor;
if gap > 0 {
match self.pass.unwrap().0 {
1 | 3 | 5 => {
pixels_per_line += 1;
}
2 => {
if gap >= 5 {
pixels_per_line += 1;
}
}
4 => {
if gap >= 3 {
pixels_per_line += 1;
}
}
6 => {
if gap >= 2 {
pixels_per_line += 1;
}
}
_ => (),
};
if gap >= x_start {
bits_per_line += bits_per_pixel - gap;
} else {
bits_per_line -= gap;
}
}
let current_pass = if let Some(pass) = self.pass {
Some(pass.0)
} else {
None
};
let bytes_per_line = (bits_per_line as f32 / 8f32).ceil() as usize;
let bytes_per_line = ((pixels_per_line * bits_per_pixel) as f32 / 8f32).ceil() as usize;
self.start = self.end;
self.end = self.start + bytes_per_line + 1;
if let Some(pass) = self.pass.as_mut() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 KiB

View file

@ -1246,3 +1246,18 @@ fn interlaced_small_files() {
png::ColorType::Indexed,
png::BitDepth::One);
}
#[test]
fn interlaced_odd_width() {
let input = PathBuf::from("tests/files/interlaced_odd_width.png");
let opts = get_opts(&input);
let output = opts.out_file.clone();
test_it_converts(&input,
&output,
&opts,
png::ColorType::RGB,
png::BitDepth::Eight,
png::ColorType::RGB,
png::BitDepth::Eight);
}