Refactor code into modules
This commit is contained in:
parent
332c27c7d0
commit
7f9ad263ec
16 changed files with 2014 additions and 1895 deletions
10
.editorconfig
Normal file
10
.editorconfig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.rs]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
**Version 0.8.3**
|
||||
- Significant refactoring
|
||||
**Version 0.9.0 (unreleased)**
|
||||
- [SEMVER_MAJOR] Significant refactoring of modules
|
||||
- Use `itertools` to cleanup areas of code
|
||||
|
||||
**Version 0.8.2**
|
||||
- Fix issue where images smaller than 4px width would crash on interlacing ([#42](https://github.com/shssoichiro/oxipng/issues/42))
|
||||
|
|
|
|||
65
Cargo.lock
generated
65
Cargo.lock
generated
|
|
@ -5,6 +5,7 @@ dependencies = [
|
|||
"bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clippy 0.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -68,6 +69,28 @@ dependencies = [
|
|||
"vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clippy_lints 0.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quine-mc_cluskey 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "1.3.0"
|
||||
|
|
@ -159,6 +182,11 @@ dependencies = [
|
|||
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
|
|
@ -176,6 +204,11 @@ dependencies = [
|
|||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.1.34"
|
||||
|
|
@ -267,6 +300,11 @@ dependencies = [
|
|||
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quine-mc_cluskey"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.14"
|
||||
|
|
@ -283,6 +321,7 @@ dependencies = [
|
|||
"aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
@ -312,6 +351,19 @@ name = "scopeguard"
|
|||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nom 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.4.1"
|
||||
|
|
@ -342,6 +394,19 @@ dependencies = [
|
|||
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.3"
|
||||
|
|
|
|||
|
|
@ -34,7 +34,15 @@ num_cpus = "^0.2.11"
|
|||
regex = "^0.1.63"
|
||||
scoped-pool = "^0.1.8"
|
||||
|
||||
[dependencies.clippy]
|
||||
optional = true
|
||||
version = "*"
|
||||
|
||||
[dev-dependencies.image]
|
||||
version = "^0.8.0"
|
||||
default-features = false
|
||||
features = ["png_codec"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
nightly = ["clippy", "regex/simd-accel"]
|
||||
|
|
|
|||
96
src/colors.rs
Normal file
96
src/colors.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Debug,PartialEq,Clone,Copy)]
|
||||
/// The color type used to represent this image
|
||||
pub enum ColorType {
|
||||
/// Grayscale, with one color channel
|
||||
Grayscale,
|
||||
/// RGB, with three color channels
|
||||
RGB,
|
||||
/// Indexed, with one byte per pixel representing one of up to 256 colors in the image
|
||||
Indexed,
|
||||
/// Grayscale + Alpha, with two color channels
|
||||
GrayscaleAlpha,
|
||||
/// RGBA, with four color channels
|
||||
RGBA,
|
||||
}
|
||||
|
||||
impl fmt::Display for ColorType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f,
|
||||
"{}",
|
||||
match *self {
|
||||
ColorType::Grayscale => "Grayscale",
|
||||
ColorType::RGB => "RGB",
|
||||
ColorType::Indexed => "Indexed",
|
||||
ColorType::GrayscaleAlpha => "Grayscale + Alpha",
|
||||
ColorType::RGBA => "RGB + Alpha",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorType {
|
||||
/// Get the code used by the PNG specification to denote this color type
|
||||
pub fn png_header_code(&self) -> u8 {
|
||||
match *self {
|
||||
ColorType::Grayscale => 0,
|
||||
ColorType::RGB => 2,
|
||||
ColorType::Indexed => 3,
|
||||
ColorType::GrayscaleAlpha => 4,
|
||||
ColorType::RGBA => 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,PartialEq,Clone,Copy)]
|
||||
/// The number of bits to be used per channel per pixel
|
||||
pub enum BitDepth {
|
||||
/// One bit per channel per pixel
|
||||
One,
|
||||
/// Two bits per channel per pixel
|
||||
Two,
|
||||
/// Four bits per channel per pixel
|
||||
Four,
|
||||
/// Eight bits per channel per pixel
|
||||
Eight,
|
||||
/// Sixteen bits per channel per pixel
|
||||
Sixteen,
|
||||
}
|
||||
|
||||
impl fmt::Display for BitDepth {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f,
|
||||
"{}",
|
||||
match *self {
|
||||
BitDepth::One => "1",
|
||||
BitDepth::Two => "2",
|
||||
BitDepth::Four => "4",
|
||||
BitDepth::Eight => "8",
|
||||
BitDepth::Sixteen => "16",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl BitDepth {
|
||||
/// Retrieve the number of bits per channel per pixel as a `u8`
|
||||
pub fn as_u8(&self) -> u8 {
|
||||
match *self {
|
||||
BitDepth::One => 1,
|
||||
BitDepth::Two => 2,
|
||||
BitDepth::Four => 4,
|
||||
BitDepth::Eight => 8,
|
||||
BitDepth::Sixteen => 16,
|
||||
}
|
||||
}
|
||||
/// Parse a number of bits per channel per pixel into a `BitDepth`
|
||||
pub fn from_u8(depth: u8) -> BitDepth {
|
||||
match depth {
|
||||
1 => BitDepth::One,
|
||||
2 => BitDepth::Two,
|
||||
4 => BitDepth::Four,
|
||||
8 => BitDepth::Eight,
|
||||
16 => BitDepth::Sixteen,
|
||||
_ => panic!("Unsupported bit depth"),
|
||||
}
|
||||
}
|
||||
}
|
||||
162
src/filters.rs
Normal file
162
src/filters.rs
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> Vec<u8> {
|
||||
let mut filtered = Vec::with_capacity(data.len());
|
||||
match filter {
|
||||
0 => {
|
||||
filtered.extend_from_slice(data);
|
||||
}
|
||||
1 => {
|
||||
filtered.extend_from_slice(&data[0..bpp]);
|
||||
filtered.extend_from_slice(&data.iter()
|
||||
.skip(bpp)
|
||||
.zip(data.iter())
|
||||
.map(|(cur, last)| cur.wrapping_sub(*last))
|
||||
.collect::<Vec<u8>>());
|
||||
}
|
||||
2 => {
|
||||
if last_line.is_empty() {
|
||||
filtered.extend_from_slice(data);
|
||||
} else {
|
||||
filtered.extend_from_slice(&data.iter()
|
||||
.zip(last_line.iter())
|
||||
.map(|(cur, last)| cur.wrapping_sub(*last))
|
||||
.collect::<Vec<u8>>());
|
||||
};
|
||||
}
|
||||
3 => {
|
||||
for (i, byte) in data.iter().enumerate() {
|
||||
if last_line.is_empty() {
|
||||
filtered.push(match i.checked_sub(bpp) {
|
||||
Some(x) => byte.wrapping_sub(data[x] >> 1),
|
||||
None => *byte,
|
||||
});
|
||||
} else {
|
||||
filtered.push(match i.checked_sub(bpp) {
|
||||
Some(x) => {
|
||||
byte.wrapping_sub(((data[x] as u16 + last_line[i] as u16) >> 1) as u8)
|
||||
}
|
||||
None => byte.wrapping_sub(last_line[i] >> 1),
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
for (i, byte) in data.iter().enumerate() {
|
||||
if last_line.is_empty() {
|
||||
filtered.push(match i.checked_sub(bpp) {
|
||||
Some(x) => byte.wrapping_sub(data[x]),
|
||||
None => *byte,
|
||||
});
|
||||
} else {
|
||||
filtered.push(match i.checked_sub(bpp) {
|
||||
Some(x) => {
|
||||
byte.wrapping_sub(paeth_predictor(data[x], last_line[i], last_line[x]))
|
||||
}
|
||||
None => byte.wrapping_sub(last_line[i]),
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
filtered
|
||||
}
|
||||
|
||||
pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> Vec<u8> {
|
||||
let mut unfiltered = Vec::with_capacity(data.len());
|
||||
match filter {
|
||||
0 => {
|
||||
unfiltered.extend_from_slice(data);
|
||||
}
|
||||
1 => {
|
||||
for (i, byte) in data.iter().enumerate() {
|
||||
match i.checked_sub(bpp) {
|
||||
Some(x) => {
|
||||
let b = unfiltered[x];
|
||||
unfiltered.push(byte.wrapping_add(b));
|
||||
}
|
||||
None => {
|
||||
unfiltered.push(*byte);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
if last_line.is_empty() {
|
||||
unfiltered.extend_from_slice(data);
|
||||
} else {
|
||||
unfiltered.extend_from_slice(&data.iter()
|
||||
.zip(last_line.iter())
|
||||
.map(|(cur, last)| cur.wrapping_add(*last))
|
||||
.collect::<Vec<u8>>());
|
||||
};
|
||||
}
|
||||
3 => {
|
||||
for (i, byte) in data.iter().enumerate() {
|
||||
if last_line.is_empty() {
|
||||
match i.checked_sub(bpp) {
|
||||
Some(x) => {
|
||||
let b = unfiltered[x];
|
||||
unfiltered.push(byte.wrapping_add(b >> 1));
|
||||
}
|
||||
None => {
|
||||
unfiltered.push(*byte);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
match i.checked_sub(bpp) {
|
||||
Some(x) => {
|
||||
let b = unfiltered[x];
|
||||
unfiltered.push(byte.wrapping_add(((b as u16 + last_line[i] as u16) >> 1) as u8));
|
||||
}
|
||||
None => {
|
||||
unfiltered.push(byte.wrapping_add(last_line[i] >> 1));
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
for (i, byte) in data.iter().enumerate() {
|
||||
if last_line.is_empty() {
|
||||
match i.checked_sub(bpp) {
|
||||
Some(x) => {
|
||||
let b = unfiltered[x];
|
||||
unfiltered.push(byte.wrapping_add(b));
|
||||
}
|
||||
None => {
|
||||
unfiltered.push(*byte);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
match i.checked_sub(bpp) {
|
||||
Some(x) => {
|
||||
let b = unfiltered[x];
|
||||
unfiltered.push(byte.wrapping_add(paeth_predictor(b,
|
||||
last_line[i],
|
||||
last_line[x])));
|
||||
}
|
||||
None => {
|
||||
unfiltered.push(byte.wrapping_add(last_line[i]));
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
unfiltered
|
||||
}
|
||||
|
||||
fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 {
|
||||
let p = a as i32 + b as i32 - c as i32;
|
||||
let pa = (p - a as i32).abs();
|
||||
let pb = (p - b as i32).abs();
|
||||
let pc = (p - c as i32).abs();
|
||||
if pa <= pb && pa <= pc {
|
||||
a
|
||||
} else if pb <= pc {
|
||||
b
|
||||
} else {
|
||||
c
|
||||
}
|
||||
}
|
||||
120
src/headers.rs
Normal file
120
src/headers.rs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use colors::{BitDepth, ColorType};
|
||||
use crc::crc32;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
/// Headers from the IHDR chunk of the image
|
||||
pub struct IhdrData {
|
||||
/// The width of the image in pixels
|
||||
pub width: u32,
|
||||
/// The height of the image in pixels
|
||||
pub height: u32,
|
||||
/// The color type of the image
|
||||
pub color_type: ColorType,
|
||||
/// The bit depth of the image
|
||||
pub bit_depth: BitDepth,
|
||||
/// The compression method used for this image (0 for DEFLATE)
|
||||
pub compression: u8,
|
||||
/// The filter mode used for this image (currently only 0 is valid)
|
||||
pub filter: u8,
|
||||
/// The interlacing mode of the image (0 = None, 1 = Adam7)
|
||||
pub interlaced: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
/// Options to use for performing operations on headers (such as stripping)
|
||||
pub enum Headers {
|
||||
/// None
|
||||
None,
|
||||
/// Some, with a list of 4-character chunk codes
|
||||
Some(Vec<String>),
|
||||
/// Headers that won't affect rendering (all but cHRM, gAMA, iCCP, sBIT, sRGB, bKGD, hIST, pHYs, sPLT)
|
||||
Safe,
|
||||
/// All non-critical headers
|
||||
All,
|
||||
}
|
||||
|
||||
pub fn file_header_is_valid(bytes: &[u8]) -> bool {
|
||||
let expected_header: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
|
||||
|
||||
bytes.iter().zip(expected_header.iter()).all(|x| x.0 == x.1)
|
||||
}
|
||||
|
||||
pub fn parse_next_header(byte_data: &[u8],
|
||||
byte_offset: &mut usize,
|
||||
fix_errors: bool)
|
||||
-> Result<Option<(String, Vec<u8>)>, String> {
|
||||
let mut rdr = Cursor::new(byte_data.iter()
|
||||
.skip(*byte_offset)
|
||||
.take(4)
|
||||
.cloned()
|
||||
.collect::<Vec<u8>>());
|
||||
let length: u32 = match rdr.read_u32::<BigEndian>() {
|
||||
Ok(x) => x,
|
||||
Err(_) => return Err("Invalid data found--unable to read PNG file".to_owned()),
|
||||
};
|
||||
*byte_offset += 4;
|
||||
|
||||
let mut header_bytes: Vec<u8> = byte_data.iter().skip(*byte_offset).take(4).cloned().collect();
|
||||
let header = match String::from_utf8(header_bytes.clone()) {
|
||||
Ok(x) => x,
|
||||
Err(_) => return Err("Invalid data found--unable to read PNG file".to_owned()),
|
||||
};
|
||||
if header == "IEND" {
|
||||
// End of data
|
||||
return Ok(None);
|
||||
}
|
||||
*byte_offset += 4;
|
||||
|
||||
let data: Vec<u8> = byte_data.iter()
|
||||
.skip(*byte_offset)
|
||||
.take(length as usize)
|
||||
.cloned()
|
||||
.collect();
|
||||
*byte_offset += length as usize;
|
||||
let mut rdr = Cursor::new(byte_data.iter()
|
||||
.skip(*byte_offset)
|
||||
.take(4)
|
||||
.cloned()
|
||||
.collect::<Vec<u8>>());
|
||||
let crc: u32 = match rdr.read_u32::<BigEndian>() {
|
||||
Ok(x) => x,
|
||||
Err(_) => return Err("Invalid data found--unable to read PNG file".to_owned()),
|
||||
};
|
||||
*byte_offset += 4;
|
||||
header_bytes.extend(data.clone());
|
||||
if !fix_errors && crc32::checksum_ieee(header_bytes.as_ref()) != crc {
|
||||
return Err(format!("Corrupt data chunk found--CRC Mismatch in {}\nThis may be recoverable by using --fix",
|
||||
header));
|
||||
}
|
||||
|
||||
Ok(Some((header, data)))
|
||||
}
|
||||
|
||||
pub fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, String> {
|
||||
let mut rdr = Cursor::new(&byte_data[0..8]);
|
||||
Ok(IhdrData {
|
||||
color_type: match byte_data[9] {
|
||||
0 => ColorType::Grayscale,
|
||||
2 => ColorType::RGB,
|
||||
3 => ColorType::Indexed,
|
||||
4 => ColorType::GrayscaleAlpha,
|
||||
6 => ColorType::RGBA,
|
||||
_ => return Err("Unexpected color type in header".to_owned()),
|
||||
},
|
||||
bit_depth: match byte_data[8] {
|
||||
1 => BitDepth::One,
|
||||
2 => BitDepth::Two,
|
||||
4 => BitDepth::Four,
|
||||
8 => BitDepth::Eight,
|
||||
16 => BitDepth::Sixteen,
|
||||
_ => return Err("Unexpected bit depth in header".to_owned()),
|
||||
},
|
||||
width: rdr.read_u32::<BigEndian>().unwrap(),
|
||||
height: rdr.read_u32::<BigEndian>().unwrap(),
|
||||
compression: byte_data[10],
|
||||
filter: byte_data[11],
|
||||
interlaced: byte_data[12],
|
||||
})
|
||||
}
|
||||
211
src/interlace.rs
Normal file
211
src/interlace.rs
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
use bit_vec::BitVec;
|
||||
use png::PngData;
|
||||
|
||||
pub fn interlace_image(png: &mut PngData) {
|
||||
let mut passes: Vec<BitVec> = vec![BitVec::new(); 7];
|
||||
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 passes that will be in the output image
|
||||
0 => {
|
||||
passes[0].extend(BitVec::from_elem(8, false));
|
||||
if png.ihdr_data.width >= 5 {
|
||||
passes[1].extend(BitVec::from_elem(8, false));
|
||||
}
|
||||
if png.ihdr_data.width >= 3 {
|
||||
passes[3].extend(BitVec::from_elem(8, false));
|
||||
}
|
||||
if png.ihdr_data.width >= 2 {
|
||||
passes[5].extend(BitVec::from_elem(8, false));
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
passes[2].extend(BitVec::from_elem(8, false));
|
||||
if png.ihdr_data.width >= 3 {
|
||||
passes[3].extend(BitVec::from_elem(8, false));
|
||||
}
|
||||
if png.ihdr_data.width >= 2 {
|
||||
passes[5].extend(BitVec::from_elem(8, false));
|
||||
}
|
||||
}
|
||||
2 | 6 => {
|
||||
passes[4].extend(BitVec::from_elem(8, false));
|
||||
if png.ihdr_data.width >= 2 {
|
||||
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) % 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;
|
||||
}
|
||||
|
||||
pub fn deinterlace_image(png: &mut PngData) {
|
||||
let bits_per_pixel = png.ihdr_data.bit_depth.as_u8() * png.channels_per_pixel();
|
||||
let bits_per_line = 8 + bits_per_pixel as usize * png.ihdr_data.width as usize;
|
||||
// Initialize each output line with a starting filter byte of 0
|
||||
// as well as some blank data
|
||||
let mut lines: Vec<BitVec> =
|
||||
vec![BitVec::from_elem(bits_per_line, false); png.ihdr_data.height as usize];
|
||||
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;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
20
src/lib.rs
20
src/lib.rs
|
|
@ -8,6 +8,7 @@ extern crate miniz_sys;
|
|||
extern crate num_cpus;
|
||||
extern crate scoped_pool;
|
||||
|
||||
use headers::Headers;
|
||||
use scoped_pool::Pool;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::{File, copy};
|
||||
|
|
@ -15,12 +16,17 @@ use std::io::{BufWriter, Write, stderr, stdout};
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub mod colors;
|
||||
pub mod deflate {
|
||||
pub mod deflate;
|
||||
pub mod libz_stream;
|
||||
pub mod miniz_stream;
|
||||
}
|
||||
mod filters;
|
||||
pub mod headers;
|
||||
mod interlace;
|
||||
pub mod png;
|
||||
mod reduction;
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
/// Options controlling the output of the `optimize` function
|
||||
|
|
@ -96,7 +102,7 @@ pub struct Options {
|
|||
pub idat_recoding: bool,
|
||||
/// Which headers to strip from the PNG file, if any
|
||||
/// Default: `None`
|
||||
pub strip: png::Headers,
|
||||
pub strip: Headers,
|
||||
/// Whether to use heuristics to pick the best filter and compression
|
||||
/// Intended for use with `-o 1` from the CLI interface
|
||||
/// Default: `false`
|
||||
|
|
@ -148,7 +154,7 @@ impl Default for Options {
|
|||
color_type_reduction: true,
|
||||
palette_reduction: true,
|
||||
idat_recoding: true,
|
||||
strip: png::Headers::None,
|
||||
strip: Headers::None,
|
||||
use_heuristics: false,
|
||||
threads: thread_count,
|
||||
}
|
||||
|
|
@ -339,7 +345,7 @@ fn optimize_png(mut png: &mut png::PngData, file_original_size: usize, opts: &Op
|
|||
if opts.use_heuristics {
|
||||
// Heuristically determine which set of options to use
|
||||
if png.ihdr_data.bit_depth.as_u8() >= 8 &&
|
||||
png.ihdr_data.color_type != png::ColorType::Indexed {
|
||||
png.ihdr_data.color_type != colors::ColorType::Indexed {
|
||||
if filter.is_empty() {
|
||||
filter.insert(5);
|
||||
}
|
||||
|
|
@ -540,13 +546,13 @@ fn report_reduction(png: &png::PngData) {
|
|||
fn perform_strip(png: &mut png::PngData, opts: &Options) {
|
||||
match opts.strip.clone() {
|
||||
// Strip headers
|
||||
png::Headers::None => (),
|
||||
png::Headers::Some(hdrs) => {
|
||||
Headers::None => (),
|
||||
Headers::Some(hdrs) => {
|
||||
for hdr in &hdrs {
|
||||
png.aux_headers.remove(hdr);
|
||||
}
|
||||
}
|
||||
png::Headers::Safe => {
|
||||
Headers::Safe => {
|
||||
const PRESERVED_HEADERS: [&'static str; 9] = ["cHRM", "gAMA", "iCCP", "sBIT", "sRGB",
|
||||
"bKGD", "hIST", "pHYs", "sPLT"];
|
||||
let mut preserved = HashMap::new();
|
||||
|
|
@ -557,7 +563,7 @@ fn perform_strip(png: &mut png::PngData, opts: &Options) {
|
|||
}
|
||||
png.aux_headers = preserved;
|
||||
}
|
||||
png::Headers::All => {
|
||||
Headers::All => {
|
||||
png.aux_headers = HashMap::new();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
src/main.rs
10
src/main.rs
|
|
@ -3,7 +3,7 @@ extern crate clap;
|
|||
extern crate regex;
|
||||
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use oxipng::png;
|
||||
use oxipng::headers::Headers;
|
||||
use regex::Regex;
|
||||
use std::collections::HashSet;
|
||||
use std::fs::DirBuilder;
|
||||
|
|
@ -475,9 +475,9 @@ fn parse_opts_into_struct(matches: &ArgMatches, opts: &mut oxipng::Options) -> R
|
|||
.to_owned());
|
||||
}
|
||||
if hdrs[0] == "safe" {
|
||||
opts.strip = png::Headers::Safe;
|
||||
opts.strip = Headers::Safe;
|
||||
} else {
|
||||
opts.strip = png::Headers::All;
|
||||
opts.strip = Headers::All;
|
||||
}
|
||||
} else {
|
||||
const FORBIDDEN_CHUNKS: [&'static str; 5] = ["IHDR", "IDAT", "tRNS", "PLTE", "IEND"];
|
||||
|
|
@ -486,12 +486,12 @@ fn parse_opts_into_struct(matches: &ArgMatches, opts: &mut oxipng::Options) -> R
|
|||
return Err(format!("{} chunk is not allowed to be stripped", i));
|
||||
}
|
||||
}
|
||||
opts.strip = png::Headers::Some(hdrs);
|
||||
opts.strip = Headers::Some(hdrs);
|
||||
}
|
||||
}
|
||||
|
||||
if matches.is_present("strip-safe") {
|
||||
opts.strip = png::Headers::Safe;
|
||||
opts.strip = Headers::Safe;
|
||||
}
|
||||
|
||||
if let Some(x) = matches.value_of("threads") {
|
||||
|
|
|
|||
938
src/png.rs
938
src/png.rs
File diff suppressed because it is too large
Load diff
339
src/reduction.rs
Normal file
339
src/reduction.rs
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
use bit_vec::BitVec;
|
||||
use colors::BitDepth;
|
||||
use itertools::Itertools;
|
||||
use png::PngData;
|
||||
|
||||
pub fn reduce_bit_depth_8_or_less(png: &PngData) -> Option<(Vec<u8>, u8)> {
|
||||
let mut reduced = BitVec::with_capacity(png.raw_data.len() * 8);
|
||||
let bit_depth: usize = png.ihdr_data.bit_depth.as_u8() as usize;
|
||||
let mut allowed_bits = 1;
|
||||
for line in png.scan_lines() {
|
||||
let bit_vec = BitVec::from_bytes(&line.data);
|
||||
for (i, bit) in bit_vec.iter().enumerate() {
|
||||
let bit_index = bit_depth - (i % bit_depth);
|
||||
if bit && bit_index > allowed_bits {
|
||||
allowed_bits = bit_index.next_power_of_two();
|
||||
if allowed_bits == bit_depth {
|
||||
// Not reducable
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for line in png.scan_lines() {
|
||||
reduced.extend(BitVec::from_bytes(&[line.filter]));
|
||||
let bit_vec = BitVec::from_bytes(&line.data);
|
||||
for (i, bit) in bit_vec.iter().enumerate() {
|
||||
let bit_index = bit_depth - (i % bit_depth);
|
||||
if bit_index <= allowed_bits {
|
||||
reduced.push(bit);
|
||||
}
|
||||
}
|
||||
// Pad end of line to get 8 bits per byte
|
||||
while reduced.len() % 8 != 0 {
|
||||
reduced.push(false);
|
||||
}
|
||||
}
|
||||
|
||||
Some((reduced.to_bytes(), allowed_bits as u8))
|
||||
}
|
||||
|
||||
pub fn reduce_rgba_to_rgb(png: &PngData) -> Option<Vec<u8>> {
|
||||
let mut reduced = Vec::with_capacity(png.raw_data.len());
|
||||
let byte_depth: u8 = png.ihdr_data.bit_depth.as_u8() >> 3;
|
||||
let bpp: usize = 4 * byte_depth as usize;
|
||||
let colored_bytes = bpp - byte_depth as usize;
|
||||
for line in png.scan_lines() {
|
||||
reduced.push(line.filter);
|
||||
for (i, byte) in line.data.iter().enumerate() {
|
||||
if i % bpp >= colored_bytes {
|
||||
if *byte != 255 {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
reduced.push(*byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(reduced)
|
||||
}
|
||||
|
||||
pub fn reduce_rgba_to_grayscale_alpha(png: &PngData) -> Option<Vec<u8>> {
|
||||
let mut reduced = Vec::with_capacity(png.raw_data.len());
|
||||
let byte_depth: u8 = png.ihdr_data.bit_depth.as_u8() >> 3;
|
||||
let bpp: usize = 4 * byte_depth as usize;
|
||||
let colored_bytes = bpp - byte_depth as usize;
|
||||
for line in png.scan_lines() {
|
||||
reduced.push(line.filter);
|
||||
let mut low_bytes = Vec::with_capacity(4);
|
||||
let mut high_bytes = Vec::with_capacity(4);
|
||||
let mut trans_bytes = Vec::with_capacity(byte_depth as usize);
|
||||
for (i, byte) in line.data.iter().enumerate() {
|
||||
if i % bpp < colored_bytes {
|
||||
if byte_depth == 1 || i % 2 == 1 {
|
||||
low_bytes.push(*byte);
|
||||
} else {
|
||||
high_bytes.push(*byte);
|
||||
}
|
||||
} else {
|
||||
trans_bytes.push(*byte);
|
||||
}
|
||||
|
||||
if i % bpp == bpp - 1 {
|
||||
if low_bytes.iter().unique().count() > 1 {
|
||||
return None;
|
||||
}
|
||||
if byte_depth == 2 {
|
||||
if high_bytes.iter().unique().count() > 1 {
|
||||
return None;
|
||||
}
|
||||
reduced.push(high_bytes[0]);
|
||||
high_bytes.clear();
|
||||
}
|
||||
reduced.push(low_bytes[0]);
|
||||
low_bytes.clear();
|
||||
reduced.extend_from_slice(&trans_bytes);
|
||||
trans_bytes.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(reduced)
|
||||
}
|
||||
|
||||
pub fn reduce_rgba_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> {
|
||||
if png.ihdr_data.bit_depth != BitDepth::Eight {
|
||||
return None;
|
||||
}
|
||||
let mut reduced = Vec::with_capacity(png.raw_data.len());
|
||||
let mut palette = Vec::with_capacity(256);
|
||||
let bpp: usize = (4 * png.ihdr_data.bit_depth.as_u8() as usize) >> 3;
|
||||
for line in png.scan_lines() {
|
||||
reduced.push(line.filter);
|
||||
let mut cur_pixel = Vec::with_capacity(bpp);
|
||||
for (i, byte) in line.data.iter().enumerate() {
|
||||
cur_pixel.push(*byte);
|
||||
if i % bpp == bpp - 1 {
|
||||
if let Some(idx) = palette.iter().position(|x| x == &cur_pixel) {
|
||||
reduced.push(idx as u8);
|
||||
} else {
|
||||
let len = palette.len();
|
||||
if len == 256 {
|
||||
return None;
|
||||
}
|
||||
palette.push(cur_pixel.clone());
|
||||
reduced.push(len as u8);
|
||||
}
|
||||
cur_pixel.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut color_palette = Vec::with_capacity(palette.len() * 3);
|
||||
let mut trans_palette = Vec::with_capacity(palette.len());
|
||||
for color in &palette {
|
||||
for (i, byte) in color.iter().enumerate() {
|
||||
if i < 3 {
|
||||
color_palette.push(*byte);
|
||||
} else {
|
||||
trans_palette.push(*byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some((reduced, color_palette, trans_palette))
|
||||
}
|
||||
|
||||
pub fn reduce_rgb_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>)> {
|
||||
if png.ihdr_data.bit_depth != BitDepth::Eight {
|
||||
return None;
|
||||
}
|
||||
let mut reduced = Vec::with_capacity(png.raw_data.len());
|
||||
let mut palette = Vec::with_capacity(256);
|
||||
let bpp: usize = (3 * png.ihdr_data.bit_depth.as_u8() as usize) >> 3;
|
||||
for line in png.scan_lines() {
|
||||
reduced.push(line.filter);
|
||||
let mut cur_pixel = Vec::with_capacity(bpp);
|
||||
for (i, byte) in line.data.iter().enumerate() {
|
||||
cur_pixel.push(*byte);
|
||||
if i % bpp == bpp - 1 {
|
||||
if let Some(idx) = palette.iter().position(|x| x == &cur_pixel) {
|
||||
reduced.push(idx as u8);
|
||||
} else {
|
||||
let len = palette.len();
|
||||
if len == 256 {
|
||||
return None;
|
||||
}
|
||||
palette.push(cur_pixel.clone());
|
||||
reduced.push(len as u8);
|
||||
}
|
||||
cur_pixel.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut color_palette = Vec::with_capacity(palette.len() * 3);
|
||||
for color in &palette {
|
||||
color_palette.extend_from_slice(color);
|
||||
}
|
||||
|
||||
Some((reduced, color_palette))
|
||||
}
|
||||
|
||||
pub fn reduce_grayscale_to_palette(png: &PngData) -> Option<(Vec<u8>, Vec<u8>)> {
|
||||
if png.ihdr_data.bit_depth == BitDepth::Sixteen {
|
||||
return None;
|
||||
}
|
||||
let mut reduced = BitVec::with_capacity(png.raw_data.len() * 8);
|
||||
// Only perform reduction if we can get to 4-bits or less
|
||||
let mut palette = Vec::with_capacity(16);
|
||||
let bpp: usize = png.ihdr_data.bit_depth.as_u8() as usize;
|
||||
let bpp_inverse = 8 - bpp;
|
||||
for line in png.scan_lines() {
|
||||
reduced.extend(BitVec::from_bytes(&[line.filter]));
|
||||
let bit_vec = BitVec::from_bytes(&line.data);
|
||||
let mut cur_pixel = BitVec::with_capacity(bpp);
|
||||
for (i, bit) in bit_vec.iter().enumerate() {
|
||||
cur_pixel.push(bit);
|
||||
if i % bpp == bpp - 1 {
|
||||
let pix_value = cur_pixel.to_bytes()[0] >> bpp_inverse;
|
||||
let pix_slice = vec![pix_value, pix_value, pix_value];
|
||||
if palette.contains(&pix_slice) {
|
||||
let index = palette.iter().enumerate().find(|&x| x.1 == &pix_slice).unwrap().0;
|
||||
let idx = BitVec::from_bytes(&[(index as u8) << bpp_inverse]);
|
||||
for b in idx.iter().take(bpp) {
|
||||
reduced.push(b);
|
||||
}
|
||||
} else {
|
||||
let len = palette.len();
|
||||
if len == 16 {
|
||||
return None;
|
||||
}
|
||||
palette.push(pix_slice.clone());
|
||||
let idx = BitVec::from_bytes(&[(len as u8) << bpp_inverse]);
|
||||
for b in idx.iter().take(bpp) {
|
||||
reduced.push(b);
|
||||
}
|
||||
}
|
||||
cur_pixel = BitVec::with_capacity(bpp);
|
||||
}
|
||||
}
|
||||
// Pad end of line to get 8 bits per byte
|
||||
while reduced.len() % 8 != 0 {
|
||||
reduced.push(false);
|
||||
}
|
||||
}
|
||||
|
||||
let mut color_palette = Vec::with_capacity(palette.len() * 3);
|
||||
for color in &palette {
|
||||
color_palette.extend_from_slice(color);
|
||||
}
|
||||
|
||||
Some((reduced.to_bytes(), color_palette))
|
||||
}
|
||||
|
||||
pub fn reduce_palette_to_grayscale(png: &PngData) -> Option<Vec<u8>> {
|
||||
let mut reduced = BitVec::with_capacity(png.raw_data.len() * 8);
|
||||
let mut cur_pixel = Vec::with_capacity(3);
|
||||
let palette = png.palette.clone().unwrap();
|
||||
// Iterate through palette and determine if all colors are grayscale
|
||||
for byte in &palette {
|
||||
cur_pixel.push(*byte);
|
||||
if cur_pixel.len() == 3 {
|
||||
if cur_pixel.iter().unique().count() > 1 {
|
||||
return None;
|
||||
}
|
||||
cur_pixel.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through scanlines and assign grayscale value to each pixel
|
||||
let bit_depth: usize = png.ihdr_data.bit_depth.as_u8() as usize;
|
||||
let bit_depth_inverse = 8 - bit_depth;
|
||||
for line in png.scan_lines() {
|
||||
reduced.extend(BitVec::from_bytes(&[line.filter]));
|
||||
let bit_vec = BitVec::from_bytes(&line.data);
|
||||
let mut cur_pixel = BitVec::with_capacity(bit_depth);
|
||||
for bit in bit_vec {
|
||||
// Handle bit depths less than 8-bits
|
||||
// At the end of each pixel, push its grayscale value onto the reduced image
|
||||
cur_pixel.push(bit);
|
||||
if cur_pixel.len() == bit_depth {
|
||||
// `to_bytes` gives us e.g. 10000000 for a 1-bit pixel, when we would want 00000001
|
||||
let padded_pixel = cur_pixel.to_bytes()[0] >> bit_depth_inverse;
|
||||
let palette_idx: usize = padded_pixel as usize * 3;
|
||||
reduced.extend(BitVec::from_bytes(&[palette[palette_idx]]));
|
||||
// BitVec's clear function doesn't set len to 0
|
||||
cur_pixel = BitVec::with_capacity(bit_depth);
|
||||
}
|
||||
}
|
||||
// Pad end of line to get 8 bits per byte
|
||||
while reduced.len() % 8 != 0 {
|
||||
reduced.push(false);
|
||||
}
|
||||
}
|
||||
|
||||
Some(reduced.to_bytes())
|
||||
}
|
||||
|
||||
pub fn reduce_rgb_to_grayscale(png: &PngData) -> Option<Vec<u8>> {
|
||||
let mut reduced = Vec::with_capacity(png.raw_data.len());
|
||||
let byte_depth: u8 = png.ihdr_data.bit_depth.as_u8() >> 3;
|
||||
let bpp: usize = 3 * byte_depth as usize;
|
||||
let mut cur_pixel = Vec::with_capacity(bpp);
|
||||
for line in png.scan_lines() {
|
||||
reduced.push(line.filter);
|
||||
for (i, byte) in line.data.iter().enumerate() {
|
||||
cur_pixel.push(*byte);
|
||||
if i % bpp == bpp - 1 {
|
||||
if bpp == 3 {
|
||||
if cur_pixel.iter().unique().count() > 1 {
|
||||
return None;
|
||||
}
|
||||
reduced.push(cur_pixel[0]);
|
||||
} else {
|
||||
let pixel_bytes = cur_pixel.iter()
|
||||
.step(2)
|
||||
.cloned()
|
||||
.zip(cur_pixel.iter()
|
||||
.skip(1)
|
||||
.step(2)
|
||||
.cloned())
|
||||
.unique()
|
||||
.collect::<Vec<(u8, u8)>>();
|
||||
if pixel_bytes.len() > 1 {
|
||||
return None;
|
||||
}
|
||||
reduced.push(pixel_bytes[0].0);
|
||||
reduced.push(pixel_bytes[0].1);
|
||||
}
|
||||
cur_pixel.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(reduced)
|
||||
}
|
||||
|
||||
pub fn reduce_grayscale_alpha_to_grayscale(png: &PngData) -> Option<Vec<u8>> {
|
||||
let mut reduced = Vec::with_capacity(png.raw_data.len());
|
||||
let byte_depth: u8 = png.ihdr_data.bit_depth.as_u8() >> 3;
|
||||
let bpp: usize = 2 * byte_depth as usize;
|
||||
let colored_bytes = bpp - byte_depth as usize;
|
||||
for line in png.scan_lines() {
|
||||
reduced.push(line.filter);
|
||||
for (i, byte) in line.data.iter().enumerate() {
|
||||
if i % bpp >= colored_bytes {
|
||||
if *byte != 255 {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
reduced.push(*byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(reduced)
|
||||
}
|
||||
545
tests/filters.rs
545
tests/filters.rs
|
|
@ -3,6 +3,7 @@ extern crate oxipng;
|
|||
|
||||
use image::GenericImage;
|
||||
use image::Pixel;
|
||||
use oxipng::colors::{BitDepth, ColorType};
|
||||
use oxipng::png;
|
||||
use std::collections::HashSet;
|
||||
use std::fs::remove_file;
|
||||
|
|
@ -24,10 +25,10 @@ fn get_opts(input: &Path) -> oxipng::Options {
|
|||
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) {
|
||||
color_type_in: ColorType,
|
||||
bit_depth_in: BitDepth,
|
||||
color_type_out: ColorType,
|
||||
bit_depth_out: BitDepth) {
|
||||
let png = png::PngData::new(input, opts.fix_errors).unwrap();
|
||||
|
||||
assert_eq!(png.ihdr_data.color_type, color_type_in);
|
||||
|
|
@ -71,10 +72,10 @@ fn filter_0_for_rgba_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -88,10 +89,10 @@ fn filter_1_for_rgba_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -105,10 +106,10 @@ fn filter_2_for_rgba_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -122,10 +123,10 @@ fn filter_3_for_rgba_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -139,10 +140,10 @@ fn filter_4_for_rgba_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -156,10 +157,10 @@ fn filter_5_for_rgba_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -173,10 +174,10 @@ fn filter_0_for_rgba_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -190,10 +191,10 @@ fn filter_1_for_rgba_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -207,10 +208,10 @@ fn filter_2_for_rgba_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -224,10 +225,10 @@ fn filter_3_for_rgba_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -241,10 +242,10 @@ fn filter_4_for_rgba_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -258,10 +259,10 @@ fn filter_5_for_rgba_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGBA,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGBA,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -275,10 +276,10 @@ fn filter_0_for_rgb_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -292,10 +293,10 @@ fn filter_1_for_rgb_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -309,10 +310,10 @@ fn filter_2_for_rgb_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -326,10 +327,10 @@ fn filter_3_for_rgb_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -343,10 +344,10 @@ fn filter_4_for_rgb_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -360,10 +361,10 @@ fn filter_5_for_rgb_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::RGB,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -377,10 +378,10 @@ fn filter_0_for_rgb_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -394,10 +395,10 @@ fn filter_1_for_rgb_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -411,10 +412,10 @@ fn filter_2_for_rgb_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -428,10 +429,10 @@ fn filter_3_for_rgb_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -445,10 +446,10 @@ fn filter_4_for_rgb_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -462,10 +463,10 @@ fn filter_5_for_rgb_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -479,10 +480,10 @@ fn filter_0_for_grayscale_alpha_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -496,10 +497,10 @@ fn filter_1_for_grayscale_alpha_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -513,10 +514,10 @@ fn filter_2_for_grayscale_alpha_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -530,10 +531,10 @@ fn filter_3_for_grayscale_alpha_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -547,10 +548,10 @@ fn filter_4_for_grayscale_alpha_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -564,10 +565,10 @@ fn filter_5_for_grayscale_alpha_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -581,10 +582,10 @@ fn filter_0_for_grayscale_alpha_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -598,10 +599,10 @@ fn filter_1_for_grayscale_alpha_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -615,10 +616,10 @@ fn filter_2_for_grayscale_alpha_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -632,10 +633,10 @@ fn filter_3_for_grayscale_alpha_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -649,10 +650,10 @@ fn filter_4_for_grayscale_alpha_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -666,10 +667,10 @@ fn filter_5_for_grayscale_alpha_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::GrayscaleAlpha,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight,
|
||||
ColorType::GrayscaleAlpha,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -683,10 +684,10 @@ fn filter_0_for_grayscale_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -700,10 +701,10 @@ fn filter_1_for_grayscale_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -717,10 +718,10 @@ fn filter_2_for_grayscale_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -734,10 +735,10 @@ fn filter_3_for_grayscale_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -751,10 +752,10 @@ fn filter_4_for_grayscale_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -768,10 +769,10 @@ fn filter_5_for_grayscale_16() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Sixteen);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Sixteen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -785,10 +786,10 @@ fn filter_0_for_grayscale_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -802,10 +803,10 @@ fn filter_1_for_grayscale_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -819,10 +820,10 @@ fn filter_2_for_grayscale_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -836,10 +837,10 @@ fn filter_3_for_grayscale_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -853,10 +854,10 @@ fn filter_4_for_grayscale_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -870,10 +871,10 @@ fn filter_5_for_grayscale_8() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::Grayscale,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight,
|
||||
ColorType::Grayscale,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -887,10 +888,10 @@ fn filter_0_for_palette_4() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -904,10 +905,10 @@ fn filter_1_for_palette_4() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -921,10 +922,10 @@ fn filter_2_for_palette_4() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -938,10 +939,10 @@ fn filter_3_for_palette_4() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -955,10 +956,10 @@ fn filter_4_for_palette_4() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -972,10 +973,10 @@ fn filter_5_for_palette_4() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Four);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Four);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -989,10 +990,10 @@ fn filter_0_for_palette_2() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1006,10 +1007,10 @@ fn filter_1_for_palette_2() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1023,10 +1024,10 @@ fn filter_2_for_palette_2() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1040,10 +1041,10 @@ fn filter_3_for_palette_2() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1057,10 +1058,10 @@ fn filter_4_for_palette_2() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1074,10 +1075,10 @@ fn filter_5_for_palette_2() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::Two);
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two,
|
||||
ColorType::Indexed,
|
||||
BitDepth::Two);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1091,10 +1092,10 @@ fn filter_0_for_palette_1() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One);
|
||||
ColorType::Indexed,
|
||||
BitDepth::One,
|
||||
ColorType::Indexed,
|
||||
BitDepth::One);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1108,10 +1109,10 @@ fn filter_1_for_palette_1() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One);
|
||||
ColorType::Indexed,
|
||||
BitDepth::One,
|
||||
ColorType::Indexed,
|
||||
BitDepth::One);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1125,10 +1126,10 @@ fn filter_2_for_palette_1() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One);
|
||||
ColorType::Indexed,
|
||||
BitDepth::One,
|
||||
ColorType::Indexed,
|
||||
BitDepth::One);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1142,10 +1143,10 @@ fn filter_3_for_palette_1() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One);
|
||||
ColorType::Indexed,
|
||||
BitDepth::One,
|
||||
ColorType::Indexed,
|
||||
BitDepth::One);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1159,10 +1160,10 @@ fn filter_4_for_palette_1() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One);
|
||||
ColorType::Indexed,
|
||||
BitDepth::One,
|
||||
ColorType::Indexed,
|
||||
BitDepth::One);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1176,10 +1177,10 @@ fn filter_5_for_palette_1() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One,
|
||||
png::ColorType::Indexed,
|
||||
png::BitDepth::One);
|
||||
ColorType::Indexed,
|
||||
BitDepth::One,
|
||||
ColorType::Indexed,
|
||||
BitDepth::One);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1193,8 +1194,8 @@ fn issue_29() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ extern crate oxipng;
|
|||
|
||||
use image::GenericImage;
|
||||
use image::Pixel;
|
||||
use oxipng::colors::{BitDepth, ColorType};
|
||||
use oxipng::headers::Headers;
|
||||
use oxipng::png;
|
||||
use std::collections::HashSet;
|
||||
use std::fs::remove_file;
|
||||
|
|
@ -24,10 +26,10 @@ fn get_opts(input: &Path) -> oxipng::Options {
|
|||
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) {
|
||||
color_type_in: ColorType,
|
||||
bit_depth_in: BitDepth,
|
||||
color_type_out: ColorType,
|
||||
bit_depth_out: BitDepth) {
|
||||
let png = png::PngData::new(input, opts.fix_errors).unwrap();
|
||||
|
||||
assert_eq!(png.ihdr_data.color_type, color_type_in);
|
||||
|
|
@ -70,17 +72,17 @@ fn verbose_mode() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strip_headers_list() {
|
||||
let input = PathBuf::from("tests/files/strip_headers_list.png");
|
||||
let mut opts = get_opts(&input);
|
||||
opts.strip = png::Headers::Some(vec!["iCCP".to_owned(), "tEXt".to_owned()]);
|
||||
opts.strip = Headers::Some(vec!["iCCP".to_owned(), "tEXt".to_owned()]);
|
||||
let output = opts.out_file.clone();
|
||||
|
||||
let png = png::PngData::new(&input, opts.fix_errors).unwrap();
|
||||
|
|
@ -121,7 +123,7 @@ fn strip_headers_list() {
|
|||
fn strip_headers_safe() {
|
||||
let input = PathBuf::from("tests/files/strip_headers_safe.png");
|
||||
let mut opts = get_opts(&input);
|
||||
opts.strip = png::Headers::Safe;
|
||||
opts.strip = Headers::Safe;
|
||||
let output = opts.out_file.clone();
|
||||
|
||||
let png = png::PngData::new(&input, opts.fix_errors).unwrap();
|
||||
|
|
@ -162,7 +164,7 @@ fn strip_headers_safe() {
|
|||
fn strip_headers_all() {
|
||||
let input = PathBuf::from("tests/files/strip_headers_all.png");
|
||||
let mut opts = get_opts(&input);
|
||||
opts.strip = png::Headers::All;
|
||||
opts.strip = Headers::All;
|
||||
let output = opts.out_file.clone();
|
||||
|
||||
let png = png::PngData::new(&input, opts.fix_errors).unwrap();
|
||||
|
|
@ -203,7 +205,7 @@ fn strip_headers_all() {
|
|||
fn strip_headers_none() {
|
||||
let input = PathBuf::from("tests/files/strip_headers_none.png");
|
||||
let mut opts = get_opts(&input);
|
||||
opts.strip = png::Headers::None;
|
||||
opts.strip = Headers::None;
|
||||
let output = opts.out_file.clone();
|
||||
|
||||
let png = png::PngData::new(&input, opts.fix_errors).unwrap();
|
||||
|
|
@ -324,8 +326,8 @@ fn interlacing_0_to_1_small_files() {
|
|||
let png = png::PngData::new(&input, opts.fix_errors).unwrap();
|
||||
|
||||
assert_eq!(png.ihdr_data.interlaced, 0);
|
||||
assert_eq!(png.ihdr_data.color_type, png::ColorType::Indexed);
|
||||
assert_eq!(png.ihdr_data.bit_depth, png::BitDepth::Eight);
|
||||
assert_eq!(png.ihdr_data.color_type, ColorType::Indexed);
|
||||
assert_eq!(png.ihdr_data.bit_depth, BitDepth::Eight);
|
||||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
|
|
@ -342,8 +344,8 @@ fn interlacing_0_to_1_small_files() {
|
|||
};
|
||||
|
||||
assert_eq!(png.ihdr_data.interlaced, 1);
|
||||
assert_eq!(png.ihdr_data.color_type, png::ColorType::Indexed);
|
||||
assert_eq!(png.ihdr_data.bit_depth, png::BitDepth::One);
|
||||
assert_eq!(png.ihdr_data.color_type, ColorType::Indexed);
|
||||
assert_eq!(png.ihdr_data.bit_depth, BitDepth::One);
|
||||
|
||||
let old_png = image::open(&input).unwrap();
|
||||
let new_png = image::open(&output).unwrap();
|
||||
|
|
@ -365,8 +367,8 @@ fn interlacing_1_to_0_small_files() {
|
|||
let png = png::PngData::new(&input, opts.fix_errors).unwrap();
|
||||
|
||||
assert_eq!(png.ihdr_data.interlaced, 1);
|
||||
assert_eq!(png.ihdr_data.color_type, png::ColorType::Indexed);
|
||||
assert_eq!(png.ihdr_data.bit_depth, png::BitDepth::Eight);
|
||||
assert_eq!(png.ihdr_data.color_type, ColorType::Indexed);
|
||||
assert_eq!(png.ihdr_data.bit_depth, BitDepth::Eight);
|
||||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
|
|
@ -383,8 +385,8 @@ fn interlacing_1_to_0_small_files() {
|
|||
};
|
||||
|
||||
assert_eq!(png.ihdr_data.interlaced, 0);
|
||||
assert_eq!(png.ihdr_data.color_type, png::ColorType::Indexed);
|
||||
assert_eq!(png.ihdr_data.bit_depth, png::BitDepth::One);
|
||||
assert_eq!(png.ihdr_data.color_type, ColorType::Indexed);
|
||||
assert_eq!(png.ihdr_data.bit_depth, BitDepth::One);
|
||||
|
||||
let old_png = image::open(&input).unwrap();
|
||||
let new_png = image::open(&output).unwrap();
|
||||
|
|
@ -446,10 +448,10 @@ fn preserve_attrs() {
|
|||
test_it_converts(&input,
|
||||
&output,
|
||||
&opts,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight,
|
||||
png::ColorType::RGB,
|
||||
png::BitDepth::Eight);
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight,
|
||||
ColorType::RGB,
|
||||
BitDepth::Eight);
|
||||
|
||||
// TODO: Actually check permissions
|
||||
}
|
||||
|
|
@ -463,8 +465,8 @@ fn fix_errors() {
|
|||
|
||||
let png = png::PngData::new(&input, opts.fix_errors).unwrap();
|
||||
|
||||
assert_eq!(png.ihdr_data.color_type, png::ColorType::RGBA);
|
||||
assert_eq!(png.ihdr_data.bit_depth, png::BitDepth::Eight);
|
||||
assert_eq!(png.ihdr_data.color_type, ColorType::RGBA);
|
||||
assert_eq!(png.ihdr_data.bit_depth, BitDepth::Eight);
|
||||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
|
|
@ -480,8 +482,8 @@ fn fix_errors() {
|
|||
}
|
||||
};
|
||||
|
||||
assert_eq!(png.ihdr_data.color_type, png::ColorType::Grayscale);
|
||||
assert_eq!(png.ihdr_data.bit_depth, png::BitDepth::Eight);
|
||||
assert_eq!(png.ihdr_data.color_type, ColorType::Grayscale);
|
||||
assert_eq!(png.ihdr_data.bit_depth, BitDepth::Eight);
|
||||
|
||||
// Cannot check if pixels are equal because image crate cannot read corrupt (input) PNGs
|
||||
remove_file(output).ok();
|
||||
|
|
@ -497,8 +499,8 @@ fn issue_42() {
|
|||
let png = png::PngData::new(&input, opts.fix_errors).unwrap();
|
||||
|
||||
assert_eq!(png.ihdr_data.interlaced, 0);
|
||||
assert_eq!(png.ihdr_data.color_type, png::ColorType::GrayscaleAlpha);
|
||||
assert_eq!(png.ihdr_data.bit_depth, png::BitDepth::Eight);
|
||||
assert_eq!(png.ihdr_data.color_type, ColorType::GrayscaleAlpha);
|
||||
assert_eq!(png.ihdr_data.bit_depth, BitDepth::Eight);
|
||||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
|
|
@ -515,8 +517,8 @@ fn issue_42() {
|
|||
};
|
||||
|
||||
assert_eq!(png.ihdr_data.interlaced, 1);
|
||||
assert_eq!(png.ihdr_data.color_type, png::ColorType::GrayscaleAlpha);
|
||||
assert_eq!(png.ihdr_data.bit_depth, png::BitDepth::Eight);
|
||||
assert_eq!(png.ihdr_data.color_type, ColorType::GrayscaleAlpha);
|
||||
assert_eq!(png.ihdr_data.bit_depth, BitDepth::Eight);
|
||||
|
||||
let old_png = image::open(&input).unwrap();
|
||||
let new_png = image::open(&output).unwrap();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue