A few inconsequential changes

This commit is contained in:
Joshua Holmer 2016-02-20 02:58:51 -05:00
parent 6c355b0c83
commit 9d48ae911e
2 changed files with 51 additions and 25 deletions

View file

@ -263,7 +263,7 @@ impl PngData {
output.append(&mut ihdr_data); output.append(&mut ihdr_data);
output.write_u32::<BigEndian>(crc).ok(); output.write_u32::<BigEndian>(crc).ok();
// Ancillary headers // Ancillary headers
for (key, header) in &self.aux_headers { for (key, header) in self.aux_headers.iter().filter(|&(ref key, _)| !(**key == "bKGD" || **key == "hIST" || **key == "tRNS")) {
let mut header_data = Vec::with_capacity(header.len() + 4); let mut header_data = Vec::with_capacity(header.len() + 4);
header_data.extend(key.as_bytes()); header_data.extend(key.as_bytes());
header_data.extend_from_slice(header); header_data.extend_from_slice(header);
@ -305,6 +305,17 @@ impl PngData {
output.append(&mut pixel_data); output.append(&mut pixel_data);
output.write_u32::<BigEndian>(crc).ok(); output.write_u32::<BigEndian>(crc).ok();
} }
// Special ancillary headers that need to come after PLTE but before IDAT
for (key, header) in self.aux_headers.iter().filter(|&(ref key, _)| **key == "bKGD" || **key == "hIST" || **key == "tRNS") {
let mut header_data = Vec::with_capacity(header.len() + 4);
header_data.extend(key.as_bytes());
header_data.extend_from_slice(header);
output.reserve(header_data.len() + 8);
output.write_u32::<BigEndian>(header_data.len() as u32 - 4).ok();
let crc = crc32::checksum_ieee(&header_data);
output.append(&mut header_data);
output.write_u32::<BigEndian>(crc).ok();
}
// IDAT data // IDAT data
let mut idat_data = Vec::with_capacity(self.idat_data.len() + 4); let mut idat_data = Vec::with_capacity(self.idat_data.len() + 4);
idat_data.extend_from_slice(b"IDAT"); idat_data.extend_from_slice(b"IDAT");
@ -788,34 +799,39 @@ fn reduce_rgba_to_grayscale_alpha(png: &PngData) -> Option<Vec<u8>> {
} }
fn reduce_rgba_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> { fn reduce_rgba_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> {
if png.ihdr_data.bit_depth != BitDepth::Eight {
return None;
}
let mut reduced = Vec::with_capacity(png.raw_data.len()); let mut reduced = Vec::with_capacity(png.raw_data.len());
let mut palette = HashMap::with_capacity(255); let mut palette = Vec::with_capacity(256);
let byte_depth: usize = (png.ihdr_data.bit_depth.as_u8() >> 3) as usize; let bpp: usize = 4;
let bpp: usize = 4 * byte_depth;
for line in png.scan_lines() { for line in png.scan_lines() {
reduced.push(line.filter); reduced.push(line.filter);
let mut cur_pixel = Vec::with_capacity(bpp); let mut cur_pixel = Vec::with_capacity(bpp);
for (i, byte) in line.data.iter().enumerate() { for (i, byte) in line.data.iter().enumerate() {
cur_pixel.push(*byte); cur_pixel.push(*byte);
if i % bpp == bpp - 1 { if i % bpp == bpp - 1 {
if !palette.contains_key(&cur_pixel) { if !palette.contains(&cur_pixel) {
let len = palette.len(); let len = palette.len();
if len >= 255 { if len == 256 {
return None; return None;
} }
palette.insert(cur_pixel.clone(), len as u8); palette.push(cur_pixel.clone());
reduced.push(len as u8);
} else {
let idx = palette.iter().enumerate().find(|&x| x.1 == &cur_pixel).unwrap().0;
reduced.push(idx as u8);
} }
reduced.push(*palette.get(&cur_pixel).unwrap());
cur_pixel.clear(); cur_pixel.clear();
} }
} }
} }
let mut color_palette = Vec::with_capacity(palette.len() * byte_depth * 3); let mut color_palette = Vec::with_capacity(palette.len() * 3);
let mut trans_palette = Vec::with_capacity(palette.len() * byte_depth); let mut trans_palette = Vec::with_capacity(palette.len());
for color in palette.keys() { for color in &palette {
for (i, byte) in color.iter().enumerate() { for (i, byte) in color.iter().enumerate() {
if i < byte_depth * 3 { if i < 3 {
color_palette.push(*byte); color_palette.push(*byte);
} else { } else {
trans_palette.push(*byte); trans_palette.push(*byte);
@ -827,31 +843,36 @@ fn reduce_rgba_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)>
} }
fn reduce_rgb_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>)> { fn reduce_rgb_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>)> {
if png.ihdr_data.bit_depth != BitDepth::Eight {
return None;
}
let mut reduced = Vec::with_capacity(png.raw_data.len()); let mut reduced = Vec::with_capacity(png.raw_data.len());
let mut palette = HashMap::with_capacity(255); let mut palette = Vec::with_capacity(256);
let byte_depth: usize = (png.ihdr_data.bit_depth.as_u8() >> 3) as usize; let bpp: usize = 3;
let bpp: usize = 3 * byte_depth;
for line in png.scan_lines() { for line in png.scan_lines() {
reduced.push(line.filter); reduced.push(line.filter);
let mut cur_pixel = Vec::with_capacity(bpp); let mut cur_pixel = Vec::with_capacity(bpp);
for (i, byte) in line.data.iter().enumerate() { for (i, byte) in line.data.iter().enumerate() {
cur_pixel.push(*byte); cur_pixel.push(*byte);
if i % bpp == bpp - 1 { if i % bpp == bpp - 1 {
if !palette.contains_key(&cur_pixel) { if !palette.contains(&cur_pixel) {
let len = palette.len(); let len = palette.len();
if len >= 255 { if len == 256 {
return None; return None;
} }
palette.insert(cur_pixel.clone(), len as u8); palette.push(cur_pixel.clone());
reduced.push(len as u8);
} else {
let idx = palette.iter().enumerate().find(|&x| x.1 == &cur_pixel).unwrap().0;
reduced.push(idx as u8);
} }
reduced.push(*palette.get(&cur_pixel).unwrap());
cur_pixel.clear(); cur_pixel.clear();
} }
} }
} }
let mut color_palette = Vec::with_capacity(palette.len() * byte_depth * 3); let mut color_palette = Vec::with_capacity(palette.len() * 3);
for color in palette.keys() { for color in &palette {
color_palette.extend_from_slice(&color); color_palette.extend_from_slice(&color);
} }

View file

@ -383,10 +383,7 @@ fn strip_headers() {
assert!(output.exists()); assert!(output.exists());
let png = match png::PngData::new(&output) { let png = match png::PngData::new(&output) {
Ok(x) => { Ok(x) => x,
remove_file(output).ok();
x
},
Err(x) => { Err(x) => {
remove_file(output).ok(); remove_file(output).ok();
panic!(x.to_owned()) panic!(x.to_owned())
@ -394,6 +391,14 @@ fn strip_headers() {
}; };
assert!(!png.aux_headers.contains_key("tEXt")); assert!(!png.aux_headers.contains_key("tEXt"));
let old_png = image::open(&input).unwrap();
let new_png = image::open(&output).unwrap();
// Conversion should be lossless
assert!(old_png.pixels().map(|x| x.2.channels().to_owned()).collect::<Vec<Vec<u8>>>() == new_png.pixels().map(|x| x.2.channels().to_owned()).collect::<Vec<Vec<u8>>>());
remove_file(output).ok();
} }
#[test] #[test]