From 9d48ae911e73a960b0a207712164a7d669a5fa74 Mon Sep 17 00:00:00 2001 From: Joshua Holmer Date: Sat, 20 Feb 2016 02:58:51 -0500 Subject: [PATCH] A few inconsequential changes --- src/png.rs | 63 ++++++++++++++++++++++++++++++++----------------- tests/oxipng.rs | 13 ++++++---- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/png.rs b/src/png.rs index 2fff074c..2aace7fb 100644 --- a/src/png.rs +++ b/src/png.rs @@ -263,7 +263,7 @@ impl PngData { output.append(&mut ihdr_data); output.write_u32::(crc).ok(); // 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); header_data.extend(key.as_bytes()); header_data.extend_from_slice(header); @@ -305,6 +305,17 @@ impl PngData { output.append(&mut pixel_data); output.write_u32::(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::(header_data.len() as u32 - 4).ok(); + let crc = crc32::checksum_ieee(&header_data); + output.append(&mut header_data); + output.write_u32::(crc).ok(); + } // IDAT data let mut idat_data = Vec::with_capacity(self.idat_data.len() + 4); idat_data.extend_from_slice(b"IDAT"); @@ -788,34 +799,39 @@ fn reduce_rgba_to_grayscale_alpha(png: &PngData) -> Option> { } fn reduce_rgba_to_palette(png: &PngData) -> Option<(Vec, Vec, Vec)> { + if png.ihdr_data.bit_depth != BitDepth::Eight { + return None; + } let mut reduced = Vec::with_capacity(png.raw_data.len()); - let mut palette = HashMap::with_capacity(255); - let byte_depth: usize = (png.ihdr_data.bit_depth.as_u8() >> 3) as usize; - let bpp: usize = 4 * byte_depth; + let mut palette = Vec::with_capacity(256); + let bpp: usize = 4; for line in png.scan_lines() { reduced.push(line.filter); let mut cur_pixel = Vec::with_capacity(bpp); for (i, byte) in line.data.iter().enumerate() { cur_pixel.push(*byte); if i % bpp == bpp - 1 { - if !palette.contains_key(&cur_pixel) { + if !palette.contains(&cur_pixel) { let len = palette.len(); - if len >= 255 { + if len == 256 { 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(); } } } - let mut color_palette = Vec::with_capacity(palette.len() * byte_depth * 3); - let mut trans_palette = Vec::with_capacity(palette.len() * byte_depth); - for color in palette.keys() { + let mut color_palette = Vec::with_capacity(palette.len() * 3); + let mut trans_palette = Vec::with_capacity(palette.len()); + for color in &palette { for (i, byte) in color.iter().enumerate() { - if i < byte_depth * 3 { + if i < 3 { color_palette.push(*byte); } else { trans_palette.push(*byte); @@ -827,31 +843,36 @@ fn reduce_rgba_to_palette(png: &PngData) -> Option<(Vec, Vec, Vec)> } fn reduce_rgb_to_palette(png: &PngData) -> Option<(Vec, Vec)> { + if png.ihdr_data.bit_depth != BitDepth::Eight { + return None; + } let mut reduced = Vec::with_capacity(png.raw_data.len()); - let mut palette = HashMap::with_capacity(255); - let byte_depth: usize = (png.ihdr_data.bit_depth.as_u8() >> 3) as usize; - let bpp: usize = 3 * byte_depth; + let mut palette = Vec::with_capacity(256); + let bpp: usize = 3; for line in png.scan_lines() { reduced.push(line.filter); let mut cur_pixel = Vec::with_capacity(bpp); for (i, byte) in line.data.iter().enumerate() { cur_pixel.push(*byte); if i % bpp == bpp - 1 { - if !palette.contains_key(&cur_pixel) { + if !palette.contains(&cur_pixel) { let len = palette.len(); - if len >= 255 { + if len == 256 { 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(); } } } - let mut color_palette = Vec::with_capacity(palette.len() * byte_depth * 3); - for color in palette.keys() { + let mut color_palette = Vec::with_capacity(palette.len() * 3); + for color in &palette { color_palette.extend_from_slice(&color); } diff --git a/tests/oxipng.rs b/tests/oxipng.rs index 4c575bab..0e6118a7 100644 --- a/tests/oxipng.rs +++ b/tests/oxipng.rs @@ -383,10 +383,7 @@ fn strip_headers() { assert!(output.exists()); let png = match png::PngData::new(&output) { - Ok(x) => { - remove_file(output).ok(); - x - }, + Ok(x) => x, Err(x) => { remove_file(output).ok(); panic!(x.to_owned()) @@ -394,6 +391,14 @@ fn strip_headers() { }; 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::>>() == new_png.pixels().map(|x| x.2.channels().to_owned()).collect::>>()); + + remove_file(output).ok(); } #[test]