Fix bug where interlaced images with certain widths would fail to optimize
This commit is contained in:
parent
1d39714b0f
commit
ecc19ad5cd
4 changed files with 50 additions and 23 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
**Version 0.8.1 (unreleased)**
|
**Version 0.8.1 (unreleased)**
|
||||||
- Minor optimizations
|
- Minor optimizations
|
||||||
|
- Fix issue where interlaced images with certain widths would fail to optimize
|
||||||
|
|
||||||
**Version 0.8.0**
|
**Version 0.8.0**
|
||||||
- [SEMVER_MINOR] Add support for optimizing PNGs already loaded into memory via library function
|
- [SEMVER_MINOR] Add support for optimizing PNGs already loaded into memory via library function
|
||||||
|
|
|
||||||
57
src/png.rs
57
src/png.rs
|
|
@ -151,58 +151,69 @@ impl<'a> Iterator for ScanLines<'a> {
|
||||||
pass.1 = 0;
|
pass.1 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let bits_per_pixel = self.png.ihdr_data.bit_depth.as_u8() as usize *
|
let bits_per_pixel = self.png.ihdr_data.bit_depth.as_u8() as u32 *
|
||||||
self.png.channels_per_pixel() as usize;
|
self.png.channels_per_pixel() as u32;
|
||||||
let mut bits_per_line = self.png.ihdr_data.width as usize * bits_per_pixel;
|
|
||||||
let y_steps;
|
let y_steps;
|
||||||
|
let pixels_factor;
|
||||||
match self.pass {
|
match self.pass {
|
||||||
Some((1, _)) | Some((2, _)) => {
|
Some((1, _)) | Some((2, _)) => {
|
||||||
bits_per_line = (bits_per_line as f32 / 8f32).ceil() as usize;
|
pixels_factor = 8;
|
||||||
y_steps = 8;
|
y_steps = 8;
|
||||||
}
|
}
|
||||||
Some((3, _)) => {
|
Some((3, _)) => {
|
||||||
bits_per_line = (bits_per_line as f32 / 4f32).ceil() as usize;
|
pixels_factor = 4;
|
||||||
y_steps = 8;
|
y_steps = 8;
|
||||||
}
|
}
|
||||||
Some((4, _)) => {
|
Some((4, _)) => {
|
||||||
bits_per_line = (bits_per_line as f32 / 4f32).ceil() as usize;
|
pixels_factor = 4;
|
||||||
y_steps = 4;
|
y_steps = 4;
|
||||||
}
|
}
|
||||||
Some((5, _)) => {
|
Some((5, _)) => {
|
||||||
bits_per_line = (bits_per_line as f32 / 2f32).ceil() as usize;
|
pixels_factor = 2;
|
||||||
y_steps = 4;
|
y_steps = 4;
|
||||||
}
|
}
|
||||||
Some((6, _)) => {
|
Some((6, _)) => {
|
||||||
bits_per_line = (bits_per_line as f32 / 2f32).ceil() as usize;
|
pixels_factor = 2;
|
||||||
y_steps = 2;
|
y_steps = 2;
|
||||||
}
|
}
|
||||||
Some((7, _)) => {
|
Some((7, _)) => {
|
||||||
|
pixels_factor = 1;
|
||||||
y_steps = 2;
|
y_steps = 2;
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
// Determine whether to trim the last (overflow) pixel for rows on this pass
|
let mut pixels_per_line = self.png.ihdr_data.width / pixels_factor as u32;
|
||||||
let gap = bits_per_line % bits_per_pixel;
|
// Determine whether to add pixels if there is a final, incomplete 8x8 block
|
||||||
if gap != 0 {
|
let gap = self.png.ihdr_data.width % pixels_factor;
|
||||||
let x_start = bits_per_pixel *
|
if gap > 0 {
|
||||||
match self.pass.unwrap().0 {
|
match self.pass.unwrap().0 {
|
||||||
2 => 4,
|
1 | 3 | 5 => {
|
||||||
4 => 2,
|
pixels_per_line += 1;
|
||||||
6 => 1,
|
}
|
||||||
_ => 0,
|
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 {
|
let current_pass = if let Some(pass) = self.pass {
|
||||||
Some(pass.0)
|
Some(pass.0)
|
||||||
} else {
|
} else {
|
||||||
None
|
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.start = self.end;
|
||||||
self.end = self.start + bytes_per_line + 1;
|
self.end = self.start + bytes_per_line + 1;
|
||||||
if let Some(pass) = self.pass.as_mut() {
|
if let Some(pass) = self.pass.as_mut() {
|
||||||
|
|
|
||||||
BIN
tests/files/interlaced_odd_width.png
Normal file
BIN
tests/files/interlaced_odd_width.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 670 KiB |
|
|
@ -1246,3 +1246,18 @@ fn interlaced_small_files() {
|
||||||
png::ColorType::Indexed,
|
png::ColorType::Indexed,
|
||||||
png::BitDepth::One);
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue