diff --git a/CHANGELOG.md b/CHANGELOG.md index 05df3afb..31edf3d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +**Version 0.3.0 (unreleased)** + - Support interlaced images + - Allow converting between progressive and interlaced images + - Fix a bug that would cause oxipng to crash on very small images + **Version 0.2.2** - Limit number of threads to 1.5x number of cores - Significantly improve memory usage, especially with high optimization levels. ([#32](https://github.com/shssoichiro/oxipng/issues/32)) diff --git a/src/deflate/deflate.rs b/src/deflate/deflate.rs index 14ddf550..312b3a33 100644 --- a/src/deflate/deflate.rs +++ b/src/deflate/deflate.rs @@ -1,5 +1,6 @@ use libz_sys; use libc::c_int; +use std::cmp::max; /// Decompress a data stream using the DEFLATE algorithm pub fn inflate(data: &[u8]) -> Result, String> { @@ -25,10 +26,12 @@ pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result, S zw as c_int, zm as c_int, zs as c_int); - let mut output = Vec::with_capacity(data.len() / 20); + // Compressed input should be smaller than decompressed, so allocate less than data.len() + // However, it needs a minimum capacity in order to handle very small images + let mut output = Vec::with_capacity(max(1024, data.len() / 20)); loop { match stream.compress_vec(input.as_mut(), output.as_mut()) { - libz_sys::Z_OK => output.reserve(data.len() / 20), + libz_sys::Z_OK => output.reserve(max(1024, data.len() / 20)), libz_sys::Z_STREAM_END => break, c => return Err(format!("Error code on compress: {}", c)), } diff --git a/src/lib.rs b/src/lib.rs index 3f054a51..c95000e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,10 +186,8 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> { if let Some(interlacing) = opts.interlace { if png.change_interlacing(interlacing) { + png.ihdr_data.interlaced = interlacing; something_changed = true; - if opts.verbosity == Some(1) { - report_reduction(&png); - } } } diff --git a/src/png.rs b/src/png.rs index 76dd27b5..33a4b58d 100644 --- a/src/png.rs +++ b/src/png.rs @@ -123,6 +123,8 @@ pub struct ScanLines<'a> { pub png: &'a PngData, start: usize, end: usize, + /// Current pass number, and 0-indexed row within the pass + pass: Option<(u8, u32)>, } impl<'a> Iterator for ScanLines<'a> { @@ -130,12 +132,97 @@ impl<'a> Iterator for ScanLines<'a> { fn next(&mut self) -> Option { if self.end == self.png.raw_data.len() { None + } else if self.png.ihdr_data.interlaced == 1 { + // Scanlines for interlaced PNG files + if self.pass.is_none() { + self.pass = Some((1, 0)); + } + // Handle edge cases for images smaller than 5 pixels in either direction + if self.png.ihdr_data.width < 5 && self.pass.unwrap().0 == 2 { + if let Some(pass) = self.pass.as_mut() { + pass.0 = 3; + pass.1 = 4; + } + } + // Intentionally keep these separate so that they can be applied one after another + if self.png.ihdr_data.height < 5 && self.pass.unwrap().0 == 3 { + if let Some(pass) = self.pass.as_mut() { + pass.0 = 4; + 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 y_steps; + match self.pass { + Some((1, _)) | Some((2, _)) => { + bits_per_line = (bits_per_line as f32 / 8f32).ceil() as usize; + y_steps = 8; + } + Some((3, _)) => { + bits_per_line = (bits_per_line as f32 / 4f32).ceil() as usize; + y_steps = 8; + } + Some((4, _)) => { + bits_per_line = (bits_per_line as f32 / 4f32).ceil() as usize; + y_steps = 4; + } + Some((5, _)) => { + bits_per_line = (bits_per_line as f32 / 2f32).ceil() as usize; + y_steps = 4; + } + Some((6, _)) => { + bits_per_line = (bits_per_line as f32 / 2f32).ceil() as usize; + y_steps = 2; + } + Some((7, _)) => { + 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, + }; + if gap >= x_start { + bits_per_line += bits_per_pixel - gap; + } else { + bits_per_line -= gap; + } + } + let bytes_per_line = (bits_per_line 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() { + if pass.1 + y_steps >= self.png.ihdr_data.height { + pass.0 += 1; + pass.1 = match pass.0 { + 3 => 4, + 5 => 2, + 7 => 1, + _ => 0, + }; + } else { + pass.1 += y_steps; + } + } + Some(ScanLine { + filter: self.png.raw_data[self.start], + data: self.png.raw_data[(self.start + 1)..self.end].to_owned(), + }) } else { + // Standard, non-interlaced PNG scanlines let bits_per_line = self.png.ihdr_data.width as usize * self.png.ihdr_data.bit_depth.as_u8() as usize * self.png.channels_per_pixel() as usize; - // Round up without converting to float - let bytes_per_line = (bits_per_line + bits_per_line % 8) >> 3; + let bytes_per_line = (bits_per_line as f32 / 8f32).ceil() as usize; self.start = self.end; self.end = self.start + bytes_per_line + 1; Some(ScanLine { @@ -338,6 +425,7 @@ impl PngData { png: &self, start: 0, end: 0, + pass: None, } } /// Reverse all filters applied on the image, returning an unfiltered IDAT bytestream @@ -542,13 +630,225 @@ impl PngData { } /// Convert the image to the specified interlacing type /// Returns true if the interlacing was changed, false otherwise + /// The `interlace` parameter specifies the *new* interlacing mode + /// Assumes that the data has already been de-filtered pub fn change_interlacing(&mut self, interlace: u8) -> bool { - // TODO: Implement - if interlace != self.ihdr_data.interlaced { + if interlace == self.ihdr_data.interlaced { return false; } - false + if interlace == 1 { + // Convert progressive to interlaced data + interlace_image(self); + } else { + // Convert interlaced to progressive data + deinterlace_image(self); + } + true + } +} + +fn interlace_image(png: &mut PngData) { + let mut passes: Vec = Vec::with_capacity(7); + for _ in 0..7 { + passes.push(BitVec::new()); + } + let bits_per_pixel = png.ihdr_data.bit_depth.as_u8() * png.channels_per_pixel(); + for (index, line) in png.scan_lines().enumerate() { + match index % 8 { + // Add filter bytes to appropriate lines + 0 => { + passes[0].extend(BitVec::from_elem(8, false)); + passes[3].extend(BitVec::from_elem(8, false)); + passes[5].extend(BitVec::from_elem(8, false)); + if png.ihdr_data.width > 4 { + passes[1].extend(BitVec::from_elem(8, false)); + } + } + 4 => { + passes[3].extend(BitVec::from_elem(8, false)); + passes[5].extend(BitVec::from_elem(8, false)); + passes[2].extend(BitVec::from_elem(8, false)); + } + 2 | 6 => { + passes[4].extend(BitVec::from_elem(8, false)); + passes[5].extend(BitVec::from_elem(8, false)); + } + _ => { + passes[6].extend(BitVec::from_elem(8, false)); + } + } + let bit_vec = BitVec::from_bytes(&line.data); + for (i, bit) in bit_vec.iter().enumerate() { + // Avoid moving padded 0's into new image + if i >= (png.ihdr_data.width * bits_per_pixel as u32) as usize { + break; + } + // Copy pixels into interlaced passes + let pix_modulo = (((i / bits_per_pixel as usize) as f32).floor() as usize) % 8; + match index % 8 { + 0 => { + match pix_modulo { + 0 => passes[0].push(bit), + 4 => passes[1].push(bit), + 2 | 6 => passes[3].push(bit), + _ => passes[5].push(bit), + } + } + 4 => { + match pix_modulo { + 0 | 4 => passes[2].push(bit), + 2 | 6 => passes[3].push(bit), + _ => passes[5].push(bit), + } + } + 2 | 6 => { + match pix_modulo % 2 { + 0 => passes[4].push(bit), + _ => passes[5].push(bit), + } + } + _ => { + passes[6].push(bit); + } + } + } + // Pad end of line on each pass to get 8 bits per byte + for pass in &mut passes { + while pass.len() % 8 != 0 { + pass.push(false); + } + } + } + let mut output = Vec::new(); + for pass in &passes { + output.extend(pass.to_bytes()); + } + png.raw_data = output; +} + +fn deinterlace_image(png: &mut PngData) { + let bits_per_pixel = png.ihdr_data.bit_depth.as_u8() * png.channels_per_pixel(); + let mut lines: Vec = Vec::with_capacity(png.ihdr_data.height as usize); + for _ in 0..png.ihdr_data.height { + // Initialize each output line with a starting filter byte of 0 + // as well as some blank data + lines.push(BitVec::from_elem(8 + bits_per_pixel as usize * png.ihdr_data.width as usize, + false)); + } + let mut current_pass = 1; + let mut pass_constants = interlaced_constants(current_pass); + let mut current_y: usize = pass_constants.y_shift as usize; + for line in png.scan_lines() { + let bit_vec = BitVec::from_bytes(&line.data); + let bits_in_line = ((png.ihdr_data.width - pass_constants.x_shift as u32) as f32 / + pass_constants.x_step as f32) + .ceil() as usize * + bits_per_pixel as usize; + for (i, bit) in bit_vec.iter().enumerate() { + // Avoid moving padded 0's into new image + if i >= bits_in_line { + break; + } + let current_x: usize = pass_constants.x_shift as usize + + (i / bits_per_pixel as usize) * pass_constants.x_step as usize; + // Copy this bit into the output line, offset by 8 because of filter byte + let index = 8 + (i % bits_per_pixel as usize) + current_x * bits_per_pixel as usize; + lines[current_y].set(index, bit); + } + // Calculate the next line and move to next pass if necessary + current_y += pass_constants.y_step as usize; + if current_y >= png.ihdr_data.height as usize { + if current_pass == 7 { + break; + } + current_pass += 1; + if current_pass == 2 && png.ihdr_data.width <= 4 { + current_pass += 1; + } + if current_pass == 3 && png.ihdr_data.height <= 4 { + current_pass += 1; + } + pass_constants = interlaced_constants(current_pass); + current_y = pass_constants.y_shift as usize; + } + } + let mut output = Vec::new(); + for line in &mut lines { + while line.len() % 8 != 0 { + line.push(false); + } + output.extend(line.to_bytes()); + } + png.raw_data = output; +} + +struct InterlacedConstants { + x_shift: u8, + y_shift: u8, + x_step: u8, + y_step: u8, +} + +fn interlaced_constants(pass: u8) -> InterlacedConstants { + match pass { + 1 => { + InterlacedConstants { + x_shift: 0, + y_shift: 0, + x_step: 8, + y_step: 8, + } + } + 2 => { + InterlacedConstants { + x_shift: 4, + y_shift: 0, + x_step: 8, + y_step: 8, + } + } + 3 => { + InterlacedConstants { + x_shift: 0, + y_shift: 4, + x_step: 4, + y_step: 8, + } + } + 4 => { + InterlacedConstants { + x_shift: 2, + y_shift: 0, + x_step: 4, + y_step: 4, + } + } + 5 => { + InterlacedConstants { + x_shift: 0, + y_shift: 2, + x_step: 2, + y_step: 4, + } + } + 6 => { + InterlacedConstants { + x_shift: 1, + y_shift: 0, + x_step: 2, + y_step: 2, + } + } + 7 => { + InterlacedConstants { + x_shift: 0, + y_shift: 1, + x_step: 1, + y_step: 2, + } + } + _ => unreachable!(), } } diff --git a/tests/files/interlaced_grayscale_16_should_be_grayscale_16.png b/tests/files/interlaced_grayscale_16_should_be_grayscale_16.png new file mode 100644 index 00000000..ede03fa8 Binary files /dev/null and b/tests/files/interlaced_grayscale_16_should_be_grayscale_16.png differ diff --git a/tests/files/interlaced_grayscale_16_should_be_grayscale_8.png b/tests/files/interlaced_grayscale_16_should_be_grayscale_8.png new file mode 100644 index 00000000..399e5dc2 Binary files /dev/null and b/tests/files/interlaced_grayscale_16_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_grayscale_16_should_be_palette_1.png b/tests/files/interlaced_grayscale_16_should_be_palette_1.png new file mode 100644 index 00000000..c83dd280 Binary files /dev/null and b/tests/files/interlaced_grayscale_16_should_be_palette_1.png differ diff --git a/tests/files/interlaced_grayscale_16_should_be_palette_2.png b/tests/files/interlaced_grayscale_16_should_be_palette_2.png new file mode 100644 index 00000000..bbe611c1 Binary files /dev/null and b/tests/files/interlaced_grayscale_16_should_be_palette_2.png differ diff --git a/tests/files/interlaced_grayscale_16_should_be_palette_4.png b/tests/files/interlaced_grayscale_16_should_be_palette_4.png new file mode 100644 index 00000000..5469aa39 Binary files /dev/null and b/tests/files/interlaced_grayscale_16_should_be_palette_4.png differ diff --git a/tests/files/interlaced_grayscale_8_should_be_grayscale_8.png b/tests/files/interlaced_grayscale_8_should_be_grayscale_8.png new file mode 100644 index 00000000..8384c4cb Binary files /dev/null and b/tests/files/interlaced_grayscale_8_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_grayscale_8_should_be_palette_1.png b/tests/files/interlaced_grayscale_8_should_be_palette_1.png new file mode 100644 index 00000000..68362afe Binary files /dev/null and b/tests/files/interlaced_grayscale_8_should_be_palette_1.png differ diff --git a/tests/files/interlaced_grayscale_8_should_be_palette_2.png b/tests/files/interlaced_grayscale_8_should_be_palette_2.png new file mode 100644 index 00000000..aa3aa0d5 Binary files /dev/null and b/tests/files/interlaced_grayscale_8_should_be_palette_2.png differ diff --git a/tests/files/interlaced_grayscale_8_should_be_palette_4.png b/tests/files/interlaced_grayscale_8_should_be_palette_4.png new file mode 100644 index 00000000..7786bf3a Binary files /dev/null and b/tests/files/interlaced_grayscale_8_should_be_palette_4.png differ diff --git a/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_16.png b/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_16.png new file mode 100644 index 00000000..dbaeb043 Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_16.png differ diff --git a/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_8.png b/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_8.png new file mode 100644 index 00000000..f55ed716 Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_16.png b/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_16.png new file mode 100644 index 00000000..f7388809 Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_16.png differ diff --git a/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_8.png b/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_8.png new file mode 100644 index 00000000..5b06dd76 Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_8.png differ diff --git a/tests/files/interlaced_grayscale_alpha_16_should_be_palette_1.png b/tests/files/interlaced_grayscale_alpha_16_should_be_palette_1.png new file mode 100644 index 00000000..7f88db48 Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_16_should_be_palette_1.png differ diff --git a/tests/files/interlaced_grayscale_alpha_16_should_be_palette_2.png b/tests/files/interlaced_grayscale_alpha_16_should_be_palette_2.png new file mode 100644 index 00000000..b7e01d3d Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_16_should_be_palette_2.png differ diff --git a/tests/files/interlaced_grayscale_alpha_16_should_be_palette_4.png b/tests/files/interlaced_grayscale_alpha_16_should_be_palette_4.png new file mode 100644 index 00000000..4cfdf1c4 Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_16_should_be_palette_4.png differ diff --git a/tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_8.png b/tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_8.png new file mode 100644 index 00000000..da52e91a Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_alpha_8.png b/tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_alpha_8.png new file mode 100644 index 00000000..cba55fcf Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_alpha_8.png differ diff --git a/tests/files/interlaced_grayscale_alpha_8_should_be_palette_1.png b/tests/files/interlaced_grayscale_alpha_8_should_be_palette_1.png new file mode 100644 index 00000000..3b1e0c7d Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_8_should_be_palette_1.png differ diff --git a/tests/files/interlaced_grayscale_alpha_8_should_be_palette_2.png b/tests/files/interlaced_grayscale_alpha_8_should_be_palette_2.png new file mode 100644 index 00000000..5cfc04b9 Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_8_should_be_palette_2.png differ diff --git a/tests/files/interlaced_grayscale_alpha_8_should_be_palette_4.png b/tests/files/interlaced_grayscale_alpha_8_should_be_palette_4.png new file mode 100644 index 00000000..bddc76ae Binary files /dev/null and b/tests/files/interlaced_grayscale_alpha_8_should_be_palette_4.png differ diff --git a/tests/files/interlaced_palette_1_should_be_palette_1.png b/tests/files/interlaced_palette_1_should_be_palette_1.png new file mode 100644 index 00000000..8fad7ec4 Binary files /dev/null and b/tests/files/interlaced_palette_1_should_be_palette_1.png differ diff --git a/tests/files/interlaced_palette_2_should_be_palette_1.png b/tests/files/interlaced_palette_2_should_be_palette_1.png new file mode 100644 index 00000000..2ae2c18f Binary files /dev/null and b/tests/files/interlaced_palette_2_should_be_palette_1.png differ diff --git a/tests/files/interlaced_palette_2_should_be_palette_2.png b/tests/files/interlaced_palette_2_should_be_palette_2.png new file mode 100644 index 00000000..d762bf9c Binary files /dev/null and b/tests/files/interlaced_palette_2_should_be_palette_2.png differ diff --git a/tests/files/interlaced_palette_4_should_be_palette_1.png b/tests/files/interlaced_palette_4_should_be_palette_1.png new file mode 100644 index 00000000..d752f06b Binary files /dev/null and b/tests/files/interlaced_palette_4_should_be_palette_1.png differ diff --git a/tests/files/interlaced_palette_4_should_be_palette_2.png b/tests/files/interlaced_palette_4_should_be_palette_2.png new file mode 100644 index 00000000..2604e434 Binary files /dev/null and b/tests/files/interlaced_palette_4_should_be_palette_2.png differ diff --git a/tests/files/interlaced_palette_4_should_be_palette_4.png b/tests/files/interlaced_palette_4_should_be_palette_4.png new file mode 100644 index 00000000..ad7906bb Binary files /dev/null and b/tests/files/interlaced_palette_4_should_be_palette_4.png differ diff --git a/tests/files/interlaced_palette_8_should_be_grayscale_8.png b/tests/files/interlaced_palette_8_should_be_grayscale_8.png new file mode 100644 index 00000000..bdb188fd Binary files /dev/null and b/tests/files/interlaced_palette_8_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_palette_8_should_be_palette_1.png b/tests/files/interlaced_palette_8_should_be_palette_1.png new file mode 100644 index 00000000..3b00238f Binary files /dev/null and b/tests/files/interlaced_palette_8_should_be_palette_1.png differ diff --git a/tests/files/interlaced_palette_8_should_be_palette_2.png b/tests/files/interlaced_palette_8_should_be_palette_2.png new file mode 100644 index 00000000..c694bfc0 Binary files /dev/null and b/tests/files/interlaced_palette_8_should_be_palette_2.png differ diff --git a/tests/files/interlaced_palette_8_should_be_palette_4.png b/tests/files/interlaced_palette_8_should_be_palette_4.png new file mode 100644 index 00000000..46088e1c Binary files /dev/null and b/tests/files/interlaced_palette_8_should_be_palette_4.png differ diff --git a/tests/files/interlaced_palette_8_should_be_palette_8.png b/tests/files/interlaced_palette_8_should_be_palette_8.png new file mode 100644 index 00000000..bf8dfa92 Binary files /dev/null and b/tests/files/interlaced_palette_8_should_be_palette_8.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_grayscale_16.png b/tests/files/interlaced_rgb_16_should_be_grayscale_16.png new file mode 100644 index 00000000..67ed56d0 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_grayscale_16.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_grayscale_8.png b/tests/files/interlaced_rgb_16_should_be_grayscale_8.png new file mode 100644 index 00000000..a769e131 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_palette_1.png b/tests/files/interlaced_rgb_16_should_be_palette_1.png new file mode 100644 index 00000000..f0fb5a56 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_palette_1.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_palette_1_grayscale.png b/tests/files/interlaced_rgb_16_should_be_palette_1_grayscale.png new file mode 100644 index 00000000..031593e3 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_palette_1_grayscale.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_palette_2.png b/tests/files/interlaced_rgb_16_should_be_palette_2.png new file mode 100644 index 00000000..7242fac1 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_palette_2.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_palette_2_grayscale.png b/tests/files/interlaced_rgb_16_should_be_palette_2_grayscale.png new file mode 100644 index 00000000..7ddc0525 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_palette_2_grayscale.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_palette_4.png b/tests/files/interlaced_rgb_16_should_be_palette_4.png new file mode 100644 index 00000000..702ac8f4 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_palette_4.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_palette_4_grayscale.png b/tests/files/interlaced_rgb_16_should_be_palette_4_grayscale.png new file mode 100644 index 00000000..bd09b398 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_palette_4_grayscale.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_palette_8.png b/tests/files/interlaced_rgb_16_should_be_palette_8.png new file mode 100644 index 00000000..45444185 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_palette_8.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_rgb_16.png b/tests/files/interlaced_rgb_16_should_be_rgb_16.png new file mode 100644 index 00000000..3be3b01f Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_rgb_16.png differ diff --git a/tests/files/interlaced_rgb_16_should_be_rgb_8.png b/tests/files/interlaced_rgb_16_should_be_rgb_8.png new file mode 100644 index 00000000..aa3768d4 Binary files /dev/null and b/tests/files/interlaced_rgb_16_should_be_rgb_8.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_grayscale_8.png b/tests/files/interlaced_rgb_8_should_be_grayscale_8.png new file mode 100644 index 00000000..53550a14 Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_palette_1.png b/tests/files/interlaced_rgb_8_should_be_palette_1.png new file mode 100644 index 00000000..4f77419e Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_palette_1.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_palette_1_grayscale.png b/tests/files/interlaced_rgb_8_should_be_palette_1_grayscale.png new file mode 100644 index 00000000..3792e688 Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_palette_1_grayscale.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_palette_2.png b/tests/files/interlaced_rgb_8_should_be_palette_2.png new file mode 100644 index 00000000..88d72a01 Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_palette_2.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_palette_2_grayscale.png b/tests/files/interlaced_rgb_8_should_be_palette_2_grayscale.png new file mode 100644 index 00000000..89008e12 Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_palette_2_grayscale.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_palette_4.png b/tests/files/interlaced_rgb_8_should_be_palette_4.png new file mode 100644 index 00000000..23be3225 Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_palette_4.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_palette_4_grayscale.png b/tests/files/interlaced_rgb_8_should_be_palette_4_grayscale.png new file mode 100644 index 00000000..d842ddbd Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_palette_4_grayscale.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_palette_8.png b/tests/files/interlaced_rgb_8_should_be_palette_8.png new file mode 100644 index 00000000..464c6cdc Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_palette_8.png differ diff --git a/tests/files/interlaced_rgb_8_should_be_rgb_8.png b/tests/files/interlaced_rgb_8_should_be_rgb_8.png new file mode 100644 index 00000000..23375db0 Binary files /dev/null and b/tests/files/interlaced_rgb_8_should_be_rgb_8.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_grayscale_16.png b/tests/files/interlaced_rgba_16_should_be_grayscale_16.png new file mode 100644 index 00000000..f2f349f6 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_grayscale_16.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_grayscale_8.png b/tests/files/interlaced_rgba_16_should_be_grayscale_8.png new file mode 100644 index 00000000..ee0245e1 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_grayscale_alpha_16.png b/tests/files/interlaced_rgba_16_should_be_grayscale_alpha_16.png new file mode 100644 index 00000000..f11382a1 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_grayscale_alpha_16.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_grayscale_alpha_8.png b/tests/files/interlaced_rgba_16_should_be_grayscale_alpha_8.png new file mode 100644 index 00000000..8131ae79 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_grayscale_alpha_8.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_palette_1.png b/tests/files/interlaced_rgba_16_should_be_palette_1.png new file mode 100644 index 00000000..8ccb3117 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_palette_1.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_palette_1_grayscale.png b/tests/files/interlaced_rgba_16_should_be_palette_1_grayscale.png new file mode 100644 index 00000000..d7b2ad9e Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_palette_1_grayscale.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_palette_2.png b/tests/files/interlaced_rgba_16_should_be_palette_2.png new file mode 100644 index 00000000..8dfee69a Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_palette_2.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_palette_2_grayscale.png b/tests/files/interlaced_rgba_16_should_be_palette_2_grayscale.png new file mode 100644 index 00000000..15623587 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_palette_2_grayscale.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_palette_4.png b/tests/files/interlaced_rgba_16_should_be_palette_4.png new file mode 100644 index 00000000..ce414935 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_palette_4.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_palette_4_grayscale.png b/tests/files/interlaced_rgba_16_should_be_palette_4_grayscale.png new file mode 100644 index 00000000..7bbf3d70 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_palette_4_grayscale.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_palette_8.png b/tests/files/interlaced_rgba_16_should_be_palette_8.png new file mode 100644 index 00000000..d5114b21 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_palette_8.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_rgb_16.png b/tests/files/interlaced_rgba_16_should_be_rgb_16.png new file mode 100644 index 00000000..9b54dded Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_rgb_16.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_rgb_8.png b/tests/files/interlaced_rgba_16_should_be_rgb_8.png new file mode 100644 index 00000000..408bbcdc Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_rgb_8.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_rgba_16.png b/tests/files/interlaced_rgba_16_should_be_rgba_16.png new file mode 100644 index 00000000..87a04b62 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_rgba_16.png differ diff --git a/tests/files/interlaced_rgba_16_should_be_rgba_8.png b/tests/files/interlaced_rgba_16_should_be_rgba_8.png new file mode 100644 index 00000000..d90811b0 Binary files /dev/null and b/tests/files/interlaced_rgba_16_should_be_rgba_8.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_grayscale_8.png b/tests/files/interlaced_rgba_8_should_be_grayscale_8.png new file mode 100644 index 00000000..fa906f8a Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_grayscale_8.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_grayscale_alpha_8.png b/tests/files/interlaced_rgba_8_should_be_grayscale_alpha_8.png new file mode 100644 index 00000000..f0484f29 Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_grayscale_alpha_8.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_palette_1.png b/tests/files/interlaced_rgba_8_should_be_palette_1.png new file mode 100644 index 00000000..5a2092a2 Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_palette_1.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_palette_1_grayscale.png b/tests/files/interlaced_rgba_8_should_be_palette_1_grayscale.png new file mode 100644 index 00000000..fcf91970 Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_palette_1_grayscale.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_palette_2.png b/tests/files/interlaced_rgba_8_should_be_palette_2.png new file mode 100644 index 00000000..1280eaba Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_palette_2.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_palette_2_grayscale.png b/tests/files/interlaced_rgba_8_should_be_palette_2_grayscale.png new file mode 100644 index 00000000..045ba467 Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_palette_2_grayscale.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_palette_4.png b/tests/files/interlaced_rgba_8_should_be_palette_4.png new file mode 100644 index 00000000..16836c5e Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_palette_4.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_palette_4_grayscale.png b/tests/files/interlaced_rgba_8_should_be_palette_4_grayscale.png new file mode 100644 index 00000000..7ee30fb9 Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_palette_4_grayscale.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_palette_8.png b/tests/files/interlaced_rgba_8_should_be_palette_8.png new file mode 100644 index 00000000..ad7cbb55 Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_palette_8.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_rgb_8.png b/tests/files/interlaced_rgba_8_should_be_rgb_8.png new file mode 100644 index 00000000..7d784854 Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_rgb_8.png differ diff --git a/tests/files/interlaced_rgba_8_should_be_rgba_8.png b/tests/files/interlaced_rgba_8_should_be_rgba_8.png new file mode 100644 index 00000000..ecef7322 Binary files /dev/null and b/tests/files/interlaced_rgba_8_should_be_rgba_8.png differ diff --git a/tests/files/interlaced_small_files.png b/tests/files/interlaced_small_files.png new file mode 100644 index 00000000..91af6176 Binary files /dev/null and b/tests/files/interlaced_small_files.png differ diff --git a/tests/files/interlacing_0_to_1.png b/tests/files/interlacing_0_to_1.png new file mode 100644 index 00000000..3f9bdb1a Binary files /dev/null and b/tests/files/interlacing_0_to_1.png differ diff --git a/tests/files/interlacing_0_to_1_small_files.png b/tests/files/interlacing_0_to_1_small_files.png new file mode 100644 index 00000000..576b88c9 Binary files /dev/null and b/tests/files/interlacing_0_to_1_small_files.png differ diff --git a/tests/files/interlacing_1_to_0.png b/tests/files/interlacing_1_to_0.png new file mode 100644 index 00000000..23375db0 Binary files /dev/null and b/tests/files/interlacing_1_to_0.png differ diff --git a/tests/files/interlacing_1_to_0_small_files.png b/tests/files/interlacing_1_to_0_small_files.png new file mode 100644 index 00000000..91af6176 Binary files /dev/null and b/tests/files/interlacing_1_to_0_small_files.png differ diff --git a/tests/files/small_files.png b/tests/files/small_files.png new file mode 100644 index 00000000..576b88c9 Binary files /dev/null and b/tests/files/small_files.png differ diff --git a/tests/flags.rs b/tests/flags.rs index cc71450b..3666809d 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -267,3 +267,159 @@ fn strip_headers_none() { remove_file(output).ok(); } + +#[test] +fn interlacing_0_to_1() { + let input = PathBuf::from("tests/files/interlacing_0_to_1.png"); + let mut opts = get_opts(&input); + opts.interlace = Some(1); + let output = opts.out_file.clone(); + + let png = png::PngData::new(&input).unwrap(); + + assert!(png.ihdr_data.interlaced == 0); + + match oxipng::optimize(&input, &opts) { + Ok(_) => (), + Err(x) => panic!(x.to_owned()), + }; + assert!(output.exists()); + + let png = match png::PngData::new(&output) { + Ok(x) => x, + Err(x) => { + remove_file(output).ok(); + panic!(x.to_owned()) + } + }; + + assert!(png.ihdr_data.interlaced == 1); + + 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] +fn interlacing_1_to_0() { + let input = PathBuf::from("tests/files/interlacing_1_to_0.png"); + let mut opts = get_opts(&input); + opts.interlace = Some(0); + let output = opts.out_file.clone(); + + let png = png::PngData::new(&input).unwrap(); + + assert!(png.ihdr_data.interlaced == 1); + + match oxipng::optimize(&input, &opts) { + Ok(_) => (), + Err(x) => panic!(x.to_owned()), + }; + assert!(output.exists()); + + let png = match png::PngData::new(&output) { + Ok(x) => x, + Err(x) => { + remove_file(output).ok(); + panic!(x.to_owned()) + } + }; + + assert!(png.ihdr_data.interlaced == 0); + + 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] +fn interlacing_0_to_1_small_files() { + let input = PathBuf::from("tests/files/interlacing_0_to_1_small_files.png"); + let mut opts = get_opts(&input); + opts.interlace = Some(1); + let output = opts.out_file.clone(); + + let png = png::PngData::new(&input).unwrap(); + + assert!(png.ihdr_data.interlaced == 0); + assert!(png.ihdr_data.color_type == png::ColorType::Indexed); + assert!(png.ihdr_data.bit_depth == png::BitDepth::Eight); + + match oxipng::optimize(&input, &opts) { + Ok(_) => (), + Err(x) => panic!(x.to_owned()), + }; + assert!(output.exists()); + + let png = match png::PngData::new(&output) { + Ok(x) => x, + Err(x) => { + remove_file(output).ok(); + panic!(x.to_owned()) + } + }; + + assert!(png.ihdr_data.interlaced == 1); + assert!(png.ihdr_data.color_type == png::ColorType::Indexed); + assert!(png.ihdr_data.bit_depth == png::BitDepth::One); + + 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] +fn interlacing_1_to_0_small_files() { + let input = PathBuf::from("tests/files/interlacing_1_to_0_small_files.png"); + let mut opts = get_opts(&input); + opts.interlace = Some(0); + let output = opts.out_file.clone(); + + let png = png::PngData::new(&input).unwrap(); + + assert!(png.ihdr_data.interlaced == 1); + assert!(png.ihdr_data.color_type == png::ColorType::Indexed); + assert!(png.ihdr_data.bit_depth == png::BitDepth::Eight); + + match oxipng::optimize(&input, &opts) { + Ok(_) => (), + Err(x) => panic!(x.to_owned()), + }; + assert!(output.exists()); + + let png = match png::PngData::new(&output) { + Ok(x) => x, + Err(x) => { + remove_file(output).ok(); + panic!(x.to_owned()) + } + }; + + assert!(png.ihdr_data.interlaced == 0); + assert!(png.ihdr_data.color_type == png::ColorType::Indexed); + assert!(png.ihdr_data.bit_depth == png::BitDepth::One); + + 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(); +} diff --git a/tests/interlaced.rs b/tests/interlaced.rs new file mode 100644 index 00000000..57df44e6 --- /dev/null +++ b/tests/interlaced.rs @@ -0,0 +1,1276 @@ +extern crate image; +extern crate oxipng; + +use image::GenericImage; +use image::Pixel; +use oxipng::png; +use std::collections::HashSet; +use std::fs::remove_file; +use std::path::Path; +use std::path::PathBuf; + +fn get_opts(input: &Path) -> oxipng::Options { + let mut filter = HashSet::new(); + filter.insert(0); + let mut compression = HashSet::new(); + compression.insert(9); + let mut memory = HashSet::new(); + memory.insert(9); + let mut strategies = HashSet::new(); + for i in 0..4 { + strategies.insert(i); + } + + oxipng::Options { + backup: false, + out_file: input.with_extension("out.png").to_owned(), + out_dir: None, + stdout: false, + pretend: false, + recursive: false, + fix_errors: false, + force: true, + clobber: true, + create: true, + preserve_attrs: false, + verbosity: None, + filter: filter, + interlace: None, + compression: compression, + memory: memory, + strategies: strategies, + window: 15, + bit_depth_reduction: true, + color_type_reduction: true, + palette_reduction: true, + idat_recoding: true, + strip: png::Headers::None, + use_heuristics: false, + } +} + +fn test_it_converts(input: &Path, + output: &Path, + opts: &oxipng::Options, + color_type_in: png::ColorType, + bit_depth_in: png::BitDepth, + color_type_out: png::ColorType, + bit_depth_out: png::BitDepth) { + let png = png::PngData::new(input).unwrap(); + + assert!(png.ihdr_data.color_type == color_type_in); + assert!(png.ihdr_data.bit_depth == bit_depth_in); + assert!(png.ihdr_data.interlaced == 1); + + match oxipng::optimize(input, opts) { + Ok(_) => (), + Err(x) => panic!(x.to_owned()), + }; + assert!(output.exists()); + + let png = match png::PngData::new(output) { + Ok(x) => x, + Err(x) => { + remove_file(output).ok(); + panic!(x.to_owned()) + } + }; + + assert!(png.ihdr_data.color_type == color_type_out); + assert!(png.ihdr_data.bit_depth == bit_depth_out); + + 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] +fn interlaced_rgba_16_should_be_rgba_16() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_rgba_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::RGBA, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_rgba_16_should_be_rgba_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_rgba_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::RGBA, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_8_should_be_rgba_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_rgba_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::RGBA, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_16_should_be_rgb_16() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_rgb_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::RGB, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_rgba_16_should_be_rgb_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_rgb_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::RGB, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_8_should_be_rgb_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_rgb_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::RGB, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_16_should_be_palette_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_palette_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_8_should_be_palette_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_palette_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_16_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_rgba_8_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_rgba_16_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_rgba_8_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_rgba_16_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_rgba_8_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_rgba_16_should_be_grayscale_alpha_16() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_grayscale_alpha_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_rgba_16_should_be_grayscale_alpha_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_grayscale_alpha_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_8_should_be_grayscale_alpha_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_grayscale_alpha_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_16_should_be_grayscale_16() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_grayscale_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Grayscale, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_rgba_16_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_grayscale_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_8_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_grayscale_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgba_16_should_be_palette_4_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_palette_4_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_rgba_8_should_be_palette_4_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_palette_4_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_rgba_16_should_be_palette_2_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_palette_2_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_rgba_8_should_be_palette_2_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_palette_2_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_rgba_16_should_be_palette_1_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_palette_1_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_rgba_8_should_be_palette_1_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_palette_1_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGBA, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_rgb_16_should_be_rgb_16() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_rgb_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::RGB, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_rgb_16_should_be_rgb_8() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_rgb_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::RGB, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgb_8_should_be_rgb_8() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_rgb_8.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); +} + +#[test] +fn interlaced_rgb_16_should_be_palette_8() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_palette_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgb_8_should_be_palette_8() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_palette_8.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::Indexed, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgb_16_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_rgb_8_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_palette_4.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::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_rgb_16_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_rgb_8_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_palette_2.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::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_rgb_16_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_rgb_8_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_palette_1.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::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_rgb_16_should_be_grayscale_16() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_grayscale_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Grayscale, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_rgb_16_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_grayscale_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgb_8_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_grayscale_8.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::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_rgb_16_should_be_palette_4_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_palette_4_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_rgb_8_should_be_palette_4_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_palette_4_grayscale.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::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_rgb_16_should_be_palette_2_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_palette_2_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_rgb_8_should_be_palette_2_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_palette_2_grayscale.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::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_rgb_16_should_be_palette_1_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgb_16_should_be_palette_1_grayscale.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::RGB, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_rgb_8_should_be_palette_1_grayscale() { + let input = PathBuf::from("tests/files/interlaced_rgb_8_should_be_palette_1_grayscale.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::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_palette_8_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_palette_8_should_be_grayscale_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Eight, + png::ColorType::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_palette_8_should_be_palette_8() { + let input = PathBuf::from("tests/files/interlaced_palette_8_should_be_palette_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_palette_8_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_palette_8_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_palette_4_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_palette_4_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Four, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_palette_8_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_palette_8_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_palette_4_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_palette_4_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Four, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_palette_2_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_palette_2_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Two, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_palette_8_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_palette_8_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_palette_4_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_palette_4_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Four, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_palette_2_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_palette_2_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Two, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_palette_1_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_palette_1_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::One, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_grayscale_alpha_16_should_be_grayscale_alpha_16() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_grayscale_alpha_16_should_be_grayscale_alpha_8() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_grayscale_alpha_8_should_be_grayscale_alpha_8() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_alpha_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_grayscale_alpha_16_should_be_grayscale_16() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen, + png::ColorType::Grayscale, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_grayscale_alpha_16_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen, + png::ColorType::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_grayscale_alpha_8_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight, + png::ColorType::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_grayscale_alpha_16_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_grayscale_alpha_8_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_8_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_grayscale_alpha_16_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_grayscale_alpha_8_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_8_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_grayscale_alpha_16_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_grayscale_alpha_8_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_8_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::GrayscaleAlpha, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_grayscale_16_should_be_grayscale_16() { + let input = PathBuf::from("tests/files/interlaced_grayscale_16_should_be_grayscale_16.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Sixteen, + png::ColorType::Grayscale, + png::BitDepth::Sixteen); +} + +#[test] +fn interlaced_grayscale_16_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_grayscale_16_should_be_grayscale_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Sixteen, + png::ColorType::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_grayscale_16_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_grayscale_16_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_grayscale_16_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_grayscale_16_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_grayscale_16_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_grayscale_16_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Sixteen, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_grayscale_8_should_be_grayscale_8() { + let input = PathBuf::from("tests/files/interlaced_grayscale_8_should_be_grayscale_8.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Eight, + png::ColorType::Grayscale, + png::BitDepth::Eight); +} + +#[test] +fn interlaced_grayscale_8_should_be_palette_4() { + let input = PathBuf::from("tests/files/interlaced_grayscale_8_should_be_palette_4.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Four); +} + +#[test] +fn interlaced_grayscale_8_should_be_palette_2() { + let input = PathBuf::from("tests/files/interlaced_grayscale_8_should_be_palette_2.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::Two); +} + +#[test] +fn interlaced_grayscale_8_should_be_palette_1() { + let input = PathBuf::from("tests/files/interlaced_grayscale_8_should_be_palette_1.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Grayscale, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::One); +} + +#[test] +fn interlaced_small_files() { + let input = PathBuf::from("tests/files/interlaced_small_files.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::One); +} diff --git a/tests/reduction.rs b/tests/reduction.rs index 6c0cafde..68704325 100644 --- a/tests/reduction.rs +++ b/tests/reduction.rs @@ -60,6 +60,7 @@ fn test_it_converts(input: &Path, assert!(png.ihdr_data.color_type == color_type_in); assert!(png.ihdr_data.bit_depth == bit_depth_in); + assert!(png.ihdr_data.interlaced == 0); match oxipng::optimize(input, opts) { Ok(_) => (), @@ -1258,3 +1259,18 @@ fn grayscale_8_should_be_palette_1() { png::ColorType::Indexed, png::BitDepth::One); } + +#[test] +fn small_files() { + let input = PathBuf::from("tests/files/small_files.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts(&input, + &output, + &opts, + png::ColorType::Indexed, + png::BitDepth::Eight, + png::ColorType::Indexed, + png::BitDepth::One); +}