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/README.md b/README.md index c18c70c7..ed0872b8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Oxipng -[![Build Status](https://travis-ci.org/shssoichiro/oxipng.svg)](https://travis-ci.org/shssoichiro/oxipng) +[![Build Status](https://travis-ci.org/shssoichiro/oxipng.svg?branch=master)](https://travis-ci.org/shssoichiro/oxipng) [![Version](https://img.shields.io/crates/v/oxipng.svg)](https://crates.io/crates/oxipng) [![License](https://img.shields.io/crates/l/oxipng.svg)](https://github.com/shssoichiro/oxipng/blob/master/LICENSE) @@ -66,7 +66,7 @@ More advanced options can be found by running `oxipng -h`. ## History -Oxipng began as a completely rewrite of the OptiPNG project, +Oxipng began as a complete rewrite of the OptiPNG project, which is assumed to be dead as no commit has been made to it since March 2014. The name has been changed to avoid confusion and potential legal issues. 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); +}