Fix a bug in palette reduction at less than 8 bits per pixel
Closes #82
This commit is contained in:
parent
6d1005d199
commit
e17f911334
4 changed files with 33 additions and 15 deletions
|
|
@ -7,7 +7,8 @@
|
||||||
trials for optimizing the alpha channel, using the previously mentioned fast heuristic.
|
trials for optimizing the alpha channel, using the previously mentioned fast heuristic.
|
||||||
This option will make optimization of images with transparency somewhat slower,
|
This option will make optimization of images with transparency somewhat slower,
|
||||||
but may improve compression.
|
but may improve compression.
|
||||||
- Fixed a bug in reducing palettes for images with bit depth of two([#80](https://github.com/shssoichiro/oxipng/issues/80))
|
- Fixed a bug in reducing palettes for images with bit depth of two ([#80](https://github.com/shssoichiro/oxipng/issues/80))
|
||||||
|
- Fixed another bug in reducing palettes for images with bit depth less than eight ([#82](https://github.com/shssoichiro/oxipng/issues/82))
|
||||||
- Code cleanup
|
- Code cleanup
|
||||||
- Update dependencies
|
- Update dependencies
|
||||||
|
|
||||||
|
|
|
||||||
28
src/png.rs
28
src/png.rs
|
|
@ -95,15 +95,15 @@ impl<'a> Iterator for ScanLines<'a> {
|
||||||
1 | 3 | 5 => {
|
1 | 3 | 5 => {
|
||||||
pixels_per_line += 1;
|
pixels_per_line += 1;
|
||||||
}
|
}
|
||||||
2 => if gap >= 5 {
|
2 if gap >= 5 => {
|
||||||
pixels_per_line += 1;
|
pixels_per_line += 1;
|
||||||
},
|
}
|
||||||
4 => if gap >= 3 {
|
4 if gap >= 3 => {
|
||||||
pixels_per_line += 1;
|
pixels_per_line += 1;
|
||||||
},
|
}
|
||||||
6 => if gap >= 2 {
|
6 if gap >= 2 => {
|
||||||
pixels_per_line += 1;
|
pixels_per_line += 1;
|
||||||
},
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +112,7 @@ impl<'a> Iterator for ScanLines<'a> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let bytes_per_line = ((pixels_per_line * bits_per_pixel) as f32 / 8f32).ceil() as usize;
|
let bytes_per_line = ((pixels_per_line * bits_per_pixel + 7) / 8) 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() {
|
||||||
|
|
@ -138,7 +138,7 @@ impl<'a> Iterator for ScanLines<'a> {
|
||||||
let bits_per_line = self.png.ihdr_data.width as usize *
|
let bits_per_line = self.png.ihdr_data.width as usize *
|
||||||
self.png.ihdr_data.bit_depth.as_u8() as usize *
|
self.png.ihdr_data.bit_depth.as_u8() as usize *
|
||||||
self.png.channels_per_pixel() as usize;
|
self.png.channels_per_pixel() as usize;
|
||||||
let bytes_per_line = (bits_per_line as f32 / 8f32).ceil() as usize;
|
let bytes_per_line = (bits_per_line + 7) / 8 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;
|
||||||
Some(ScanLine {
|
Some(ScanLine {
|
||||||
|
|
@ -588,13 +588,13 @@ impl PngData {
|
||||||
|
|
||||||
fn do_palette_reduction(
|
fn do_palette_reduction(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &[u8],
|
indices_to_remove: &[u8],
|
||||||
index_map: &mut HashMap<u8, u8>,
|
index_map: &mut HashMap<u8, u8>,
|
||||||
indexed_palette: &mut Vec<&[u8]>,
|
indexed_palette: &mut Vec<&[u8]>,
|
||||||
) {
|
) {
|
||||||
let mut new_data = Vec::with_capacity(self.raw_data.len());
|
let mut new_data = Vec::with_capacity(self.raw_data.len());
|
||||||
let original_len = indexed_palette.len();
|
let original_len = indexed_palette.len();
|
||||||
for idx in indices.iter().sorted_by(|a, b| b.cmp(a)) {
|
for idx in indices_to_remove.iter().sorted_by(|a, b| b.cmp(a)) {
|
||||||
for i in (*idx as usize + 1)..original_len {
|
for i in (*idx as usize + 1)..original_len {
|
||||||
let existing = index_map.entry(i as u8).or_insert(i as u8);
|
let existing = index_map.entry(i as u8).or_insert(i as u8);
|
||||||
if *existing >= *idx {
|
if *existing >= *idx {
|
||||||
|
|
@ -628,7 +628,7 @@ impl PngData {
|
||||||
let upper = *byte & 0b1111_0000;
|
let upper = *byte & 0b1111_0000;
|
||||||
let lower = *byte & 0b0000_1111;
|
let lower = *byte & 0b0000_1111;
|
||||||
let mut new_byte = 0u8;
|
let mut new_byte = 0u8;
|
||||||
new_byte |= if let Some(new_idx) = index_map.get(&upper) {
|
new_byte |= if let Some(new_idx) = index_map.get(&(upper >> 4)) {
|
||||||
*new_idx << 4
|
*new_idx << 4
|
||||||
} else {
|
} else {
|
||||||
upper
|
upper
|
||||||
|
|
@ -646,17 +646,17 @@ impl PngData {
|
||||||
let three = *byte & 0b0000_1100;
|
let three = *byte & 0b0000_1100;
|
||||||
let four = *byte & 0b0000_0011;
|
let four = *byte & 0b0000_0011;
|
||||||
let mut new_byte = 0u8;
|
let mut new_byte = 0u8;
|
||||||
new_byte |= if let Some(new_idx) = index_map.get(&one) {
|
new_byte |= if let Some(new_idx) = index_map.get(&(one >> 6)) {
|
||||||
*new_idx << 6
|
*new_idx << 6
|
||||||
} else {
|
} else {
|
||||||
one
|
one
|
||||||
};
|
};
|
||||||
new_byte |= if let Some(new_idx) = index_map.get(&two) {
|
new_byte |= if let Some(new_idx) = index_map.get(&(two >> 4)) {
|
||||||
*new_idx << 4
|
*new_idx << 4
|
||||||
} else {
|
} else {
|
||||||
two
|
two
|
||||||
};
|
};
|
||||||
new_byte |= if let Some(new_idx) = index_map.get(&three) {
|
new_byte |= if let Some(new_idx) = index_map.get(&(three >> 2)) {
|
||||||
*new_idx << 2
|
*new_idx << 2
|
||||||
} else {
|
} else {
|
||||||
three
|
three
|
||||||
|
|
|
||||||
BIN
tests/files/issue-82.png
Normal file
BIN
tests/files/issue-82.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 455 B |
|
|
@ -291,3 +291,20 @@ fn issue_80() {
|
||||||
BitDepth::One,
|
BitDepth::One,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn issue_82() {
|
||||||
|
let input = PathBuf::from("tests/files/issue-82.png");
|
||||||
|
let opts = get_opts(&input);
|
||||||
|
let output = opts.out_file.clone();
|
||||||
|
|
||||||
|
test_it_converts(
|
||||||
|
&input,
|
||||||
|
&output,
|
||||||
|
&opts,
|
||||||
|
ColorType::Indexed,
|
||||||
|
BitDepth::Four,
|
||||||
|
ColorType::Indexed,
|
||||||
|
BitDepth::Four,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue