parent
723c0c29fb
commit
d99db3ad23
13 changed files with 129 additions and 96 deletions
|
|
@ -11,7 +11,7 @@ matrix:
|
|||
env: TARGET=x86_64-apple-darwin
|
||||
cache: cargo
|
||||
- os: linux
|
||||
rust: 1.8.0
|
||||
rust: 1.9.0
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
cache: cargo
|
||||
- os: linux
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
**Version 0.11.0 (unreleased)**
|
||||
- [SEMVER_MAJOR] Bump minimum rustc version to 1.8.0, required by dependencies
|
||||
- [SEMVER_MAJOR] Bump minimum rustc version to 1.9.0, required by dependencies
|
||||
- [SEMVER_MINOR] Allow calling optimization presets via crate using `Options::from_preset`
|
||||
- [SEMVER_MAJOR] Return proper `PngError` type which implements `std::error::Error` from `Result`s
|
||||
|
||||
**Version 0.10.0**
|
||||
- [SEMVER_MINOR] Make clap and regex dependencies optional
|
||||
|
|
|
|||
48
Cargo.lock
generated
48
Cargo.lock
generated
|
|
@ -7,9 +7,9 @@ dependencies = [
|
|||
"clap 2.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clippy 0.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libz-sys 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -52,7 +52,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"ansi_term 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -73,7 +73,7 @@ version = "0.0.81"
|
|||
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.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quine-mc_cluskey 0.2.4 (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)",
|
||||
|
|
@ -91,7 +91,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -107,7 +107,7 @@ name = "flate2"
|
|||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.10.1"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -142,7 +142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.4.17"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -161,7 +161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.14"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -170,7 +170,7 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ name = "memchr"
|
|||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -193,7 +193,7 @@ version = "0.1.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -260,7 +260,7 @@ name = "num_cpus"
|
|||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -281,7 +281,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quine-mc_cluskey"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -289,7 +289,7 @@ name = "rand"
|
|||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -320,7 +320,7 @@ name = "scoped-pool"
|
|||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"variance 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
@ -353,7 +353,7 @@ name = "term_size"
|
|||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -362,7 +362,7 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -426,17 +426,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum clippy 0.0.81 (registry+https://github.com/rust-lang/crates.io-index)" = "4eb4e734b771514b74b44e0d04e176e572d6e0637e32fe112331a0063a22ef39"
|
||||
"checksum clippy_lints 0.0.81 (registry+https://github.com/rust-lang/crates.io-index)" = "cd863204278a2011c4bf82417e7e8b869afd949410ce8d0dab14da2c79b96af9"
|
||||
"checksum crc 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a3f9159e74024e2cdb6f574e9117cdc2e91523a890930a022823d17abedc90a"
|
||||
"checksum crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "fb974f835e90390c5f9dfac00f05b06dc117299f5ea4e85fbc7bb443af4911cc"
|
||||
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
||||
"checksum enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f79eff5be92a4d7d5bddf7daa7d650717ea71628634efe6ca7bcda85b2183c23"
|
||||
"checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb"
|
||||
"checksum gcc 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb000abd6df9df4c637f75190297ebe56c1d7e66b56bbf3b4aa7aece15f61a2"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7cd7efa3558b1acd537f2a6f9bcf15c4ae4842da38d2e2ea7c9ad023f36239b"
|
||||
"checksum image 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "559d5ebbe9ec73111799e49c07717944b244f8accf5de33a8a8128bc3ecd2e00"
|
||||
"checksum inflate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7e0062d2dc2f17d2f13750d95316ae8a2ff909af0fda957084f5defd87c43bb"
|
||||
"checksum itertools 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7ddb83e0e9730d830afba4e6839077948b4efa22075f7cd80a3867ec286c610f"
|
||||
"checksum itertools 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6f15d694e7f7d46ef7a6951db981b33f132472f91d11b5a0f44d3980b87ccbc3"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
||||
"checksum libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "39dfaaa0f4da0f1a06876c5d94329d739ad0150868069cc235f1ddf80a0480e7"
|
||||
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
|
||||
"checksum libz-sys 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ab80d82d16acfbf5c0e731297db302378896c0cffbc428dddc61d995a82e15cf"
|
||||
"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
|
|
@ -451,7 +451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum num_cpus 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a859041cbf7a70ea1ece4b87d1a2c6ef364dcb68749c88db1f97304b9ec09d5f"
|
||||
"checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa"
|
||||
"checksum png 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "06208e2ee243e3118a55dda9318f821f206d8563fb8d4df258767f8e62bb0997"
|
||||
"checksum quine-mc_cluskey 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8f9a75e9319beed349f32bb252bcd7cafe4cce6c57a9ddcc9a8ffd3c49c3659"
|
||||
"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
|
||||
"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
|
||||
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
|
||||
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ cp target/release/oxipng /usr/local/bin
|
|||
Please note that zlib is a required build dependency. Oxipng should work with any 1.x version of zlib,
|
||||
but you are advised to use the latest version (currently 1.2.8) for security and bug fixes.
|
||||
|
||||
The current minimum supported Rust version is **1.8.0**. Oxipng may compile on earlier versions of Rust,
|
||||
The current minimum supported Rust version is **1.9.0**. Oxipng may compile on earlier versions of Rust,
|
||||
but there is no guarantee.
|
||||
|
||||
Oxipng follows Semantic Versioning.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use error::PngError;
|
||||
use libz_sys;
|
||||
use miniz_sys;
|
||||
use libc::c_int;
|
||||
use std::cmp::max;
|
||||
|
||||
/// Decompress a data stream using the DEFLATE algorithm
|
||||
pub fn inflate(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
pub fn inflate(data: &[u8]) -> Result<Vec<u8>, PngError> {
|
||||
let mut input = data.to_owned();
|
||||
let mut stream = super::libz_stream::Stream::new_decompress();
|
||||
let mut output = Vec::with_capacity(data.len());
|
||||
|
|
@ -12,7 +13,7 @@ pub fn inflate(data: &[u8]) -> Result<Vec<u8>, String> {
|
|||
match stream.decompress_vec(input.as_mut(), output.as_mut()) {
|
||||
libz_sys::Z_OK => output.reserve(data.len()),
|
||||
libz_sys::Z_STREAM_END => break,
|
||||
c => return Err(format!("Error code on decompress: {}", c)),
|
||||
c => return Err(PngError::new(&format!("Error code on decompress: {}", c))),
|
||||
}
|
||||
}
|
||||
output.shrink_to_fit();
|
||||
|
|
@ -21,7 +22,7 @@ pub fn inflate(data: &[u8]) -> Result<Vec<u8>, String> {
|
|||
}
|
||||
|
||||
/// Compress a data stream using the zlib implementation of the DEFLATE algorithm
|
||||
pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result<Vec<u8>, String> {
|
||||
pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result<Vec<u8>, PngError> {
|
||||
let mut input = data.to_owned();
|
||||
// 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
|
||||
|
|
@ -36,7 +37,7 @@ pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result<Vec<u8>, S
|
|||
match stream.compress_vec(input.as_mut(), output.as_mut()) {
|
||||
miniz_sys::MZ_OK => output.reserve(max(1024, data.len() / 20)),
|
||||
miniz_sys::MZ_STREAM_END => break,
|
||||
c => return Err(format!("Error code on compress: {}", c)),
|
||||
c => return Err(PngError::new(&format!("Error code on compress: {}", c))),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -49,7 +50,7 @@ pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result<Vec<u8>, S
|
|||
match stream.compress_vec(input.as_mut(), output.as_mut()) {
|
||||
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)),
|
||||
c => return Err(PngError::new(&format!("Error code on compress: {}", c))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
src/error.rs
Normal file
25
src/error.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PngError {
|
||||
description: String,
|
||||
}
|
||||
|
||||
impl Error for PngError {
|
||||
fn description(&self) -> &str {
|
||||
&self.description
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PngError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.description)
|
||||
}
|
||||
}
|
||||
|
||||
impl PngError {
|
||||
pub fn new(description: &str) -> PngError {
|
||||
PngError { description: description.to_owned() }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use colors::{BitDepth, ColorType};
|
||||
use crc::crc32;
|
||||
use error::PngError;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
@ -45,7 +46,7 @@ pub fn file_header_is_valid(bytes: &[u8]) -> bool {
|
|||
pub fn parse_next_header(byte_data: &[u8],
|
||||
byte_offset: &mut usize,
|
||||
fix_errors: bool)
|
||||
-> Result<Option<(String, Vec<u8>)>, String> {
|
||||
-> Result<Option<(String, Vec<u8>)>, PngError> {
|
||||
let mut rdr = Cursor::new(byte_data.iter()
|
||||
.skip(*byte_offset)
|
||||
.take(4)
|
||||
|
|
@ -53,14 +54,14 @@ pub fn parse_next_header(byte_data: &[u8],
|
|||
.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()),
|
||||
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
||||
};
|
||||
*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()),
|
||||
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
||||
};
|
||||
if header == "IEND" {
|
||||
// End of data
|
||||
|
|
@ -81,19 +82,19 @@ pub fn parse_next_header(byte_data: &[u8],
|
|||
.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()),
|
||||
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
||||
};
|
||||
*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));
|
||||
return Err(PngError::new(&format!("CRC Mismatch in {} header; May be recoverable by using --fix",
|
||||
header)));
|
||||
}
|
||||
|
||||
Ok(Some((header, data)))
|
||||
}
|
||||
|
||||
pub fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, String> {
|
||||
pub fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, PngError> {
|
||||
let mut rdr = Cursor::new(&byte_data[0..8]);
|
||||
Ok(IhdrData {
|
||||
color_type: match byte_data[9] {
|
||||
|
|
@ -102,7 +103,7 @@ pub fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, String> {
|
|||
3 => ColorType::Indexed,
|
||||
4 => ColorType::GrayscaleAlpha,
|
||||
6 => ColorType::RGBA,
|
||||
_ => return Err("Unexpected color type in header".to_owned()),
|
||||
_ => return Err(PngError::new("Unexpected color type in header")),
|
||||
},
|
||||
bit_depth: match byte_data[8] {
|
||||
1 => BitDepth::One,
|
||||
|
|
@ -110,7 +111,7 @@ pub fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, String> {
|
|||
4 => BitDepth::Four,
|
||||
8 => BitDepth::Eight,
|
||||
16 => BitDepth::Sixteen,
|
||||
_ => return Err("Unexpected bit depth in header".to_owned()),
|
||||
_ => return Err(PngError::new("Unexpected bit depth in header")),
|
||||
},
|
||||
width: rdr.read_u32::<BigEndian>().unwrap(),
|
||||
height: rdr.read_u32::<BigEndian>().unwrap(),
|
||||
|
|
|
|||
18
src/lib.rs
18
src/lib.rs
|
|
@ -8,6 +8,7 @@ extern crate miniz_sys;
|
|||
extern crate num_cpus;
|
||||
extern crate scoped_pool;
|
||||
|
||||
use error::PngError;
|
||||
use headers::Headers;
|
||||
use scoped_pool::Pool;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
|
@ -22,6 +23,7 @@ pub mod deflate {
|
|||
pub mod libz_stream;
|
||||
pub mod miniz_stream;
|
||||
}
|
||||
mod error;
|
||||
mod filters;
|
||||
pub mod headers;
|
||||
mod interlace;
|
||||
|
|
@ -270,7 +272,7 @@ impl Default for Options {
|
|||
}
|
||||
|
||||
/// Perform optimization on the input file using the options provided
|
||||
pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
|
||||
pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> {
|
||||
// Read in the file and try to decode as PNG.
|
||||
if opts.verbosity.is_some() {
|
||||
writeln!(&mut stderr(), "Processing: {}", filepath.to_str().unwrap()).ok();
|
||||
|
|
@ -305,8 +307,8 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
|
|||
.unwrap()))) {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
return Err(format!("Unable to write to backup file at {}",
|
||||
opts.out_file.display()))
|
||||
return Err(PngError::new(&format!("Unable to write to backup file at {}",
|
||||
opts.out_file.display())))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -315,13 +317,14 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
|
|||
let mut buffer = BufWriter::new(stdout());
|
||||
match buffer.write_all(&optimized_output) {
|
||||
Ok(_) => (),
|
||||
Err(_) => return Err("Unable to write to stdout".to_owned()),
|
||||
Err(_) => return Err(PngError::new("Unable to write to stdout")),
|
||||
}
|
||||
} else {
|
||||
let out_file = match File::create(&opts.out_file) {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
return Err(format!("Unable to write to file {}", opts.out_file.display()))
|
||||
return Err(PngError::new(&format!("Unable to write to file {}",
|
||||
opts.out_file.display())))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -377,7 +380,8 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(format!("Unable to write to file {}", opts.out_file.display()))
|
||||
return Err(PngError::new(&format!("Unable to write to file {}",
|
||||
opts.out_file.display())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -387,7 +391,7 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
|
|||
|
||||
/// Perform optimization on the input file using the options provided, where the file is already
|
||||
/// loaded in-memory
|
||||
pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result<Vec<u8>, String> {
|
||||
pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result<Vec<u8>, PngError> {
|
||||
// Read in the file and try to decode as PNG.
|
||||
if opts.verbosity.is_some() {
|
||||
writeln!(&mut stderr(), "Processing from memory").ok();
|
||||
|
|
|
|||
21
src/png.rs
21
src/png.rs
|
|
@ -2,6 +2,7 @@ use bit_vec::BitVec;
|
|||
use byteorder::{BigEndian, WriteBytesExt};
|
||||
use colors::{BitDepth, ColorType};
|
||||
use crc::crc32;
|
||||
use error::PngError;
|
||||
use filters::*;
|
||||
use headers::*;
|
||||
use interlace::{interlace_image, deinterlace_image};
|
||||
|
|
@ -181,28 +182,28 @@ pub struct PngData {
|
|||
|
||||
impl PngData {
|
||||
/// Create a new `PngData` struct by opening a file
|
||||
pub fn new(filepath: &Path, fix_errors: bool) -> Result<PngData, String> {
|
||||
pub fn new(filepath: &Path, fix_errors: bool) -> Result<PngData, PngError> {
|
||||
let mut file = match File::open(filepath) {
|
||||
Ok(f) => f,
|
||||
Err(_) => return Err("Failed to open file for reading".to_owned()),
|
||||
Err(_) => return Err(PngError::new("Failed to open file for reading")),
|
||||
};
|
||||
let mut byte_data: Vec<u8> = Vec::new();
|
||||
// Read raw png data into memory
|
||||
match file.read_to_end(&mut byte_data) {
|
||||
Ok(_) => (),
|
||||
Err(_) => return Err("Failed to read from file".to_owned()),
|
||||
Err(_) => return Err(PngError::new("Failed to read from file")),
|
||||
}
|
||||
|
||||
PngData::from_slice(&byte_data, fix_errors)
|
||||
}
|
||||
|
||||
/// Create a new `PngData` struct by reading a slice
|
||||
pub fn from_slice(byte_data: &[u8], fix_errors: bool) -> Result<PngData, String> {
|
||||
pub fn from_slice(byte_data: &[u8], fix_errors: bool) -> Result<PngData, PngError> {
|
||||
let mut byte_offset: usize = 0;
|
||||
// Test that png header is valid
|
||||
let header: Vec<u8> = byte_data.iter().take(8).cloned().collect();
|
||||
if !file_header_is_valid(header.as_ref()) {
|
||||
return Err("Invalid PNG header detected".to_owned());
|
||||
return Err(PngError::new("Invalid PNG header detected"));
|
||||
}
|
||||
byte_offset += 8;
|
||||
// Read the data headers
|
||||
|
|
@ -226,10 +227,10 @@ impl PngData {
|
|||
}
|
||||
// Parse the headers into our PngData
|
||||
if idat_headers.is_empty() {
|
||||
return Err("Image data was empty, skipping".to_owned());
|
||||
return Err(PngError::new("Image data was empty, skipping"));
|
||||
}
|
||||
if aux_headers.get("IHDR").is_none() {
|
||||
return Err("Image header data was missing, skipping".to_owned());
|
||||
return Err(PngError::new("Image header data was missing, skipping"));
|
||||
}
|
||||
let ihdr_header = match parse_ihdr_header(aux_headers.remove("IHDR").unwrap().as_ref()) {
|
||||
Ok(x) => x,
|
||||
|
|
@ -388,11 +389,7 @@ impl PngData {
|
|||
// http://www.libpng.org/pub/png/book/chapter09.html
|
||||
let mut trials: HashMap<u8, Vec<u8>> = HashMap::with_capacity(5);
|
||||
// Avoid vertical filtering on first line of each interlacing pass
|
||||
for filter in if last_pass == line.pass {
|
||||
0..5
|
||||
} else {
|
||||
0..2
|
||||
} {
|
||||
for filter in if last_pass == line.pass { 0..5 } else { 0..2 } {
|
||||
trials.insert(filter, filter_line(filter, bpp, &line.data, &last_line));
|
||||
}
|
||||
let (best_filter, best_line) = trials.iter()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use image::Pixel;
|
|||
use oxipng::colors::{BitDepth, ColorType};
|
||||
use oxipng::png;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
use std::fs::remove_file;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -36,7 +37,7 @@ fn test_it_converts(input: &Path,
|
|||
|
||||
match oxipng::optimize(input, opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -44,7 +45,7 @@ fn test_it_converts(input: &Path,
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use oxipng::colors::{BitDepth, ColorType};
|
|||
use oxipng::headers::Headers;
|
||||
use oxipng::png;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
use std::fs::remove_file;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -37,7 +38,7 @@ fn test_it_converts(input: &Path,
|
|||
|
||||
match oxipng::optimize(input, opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ fn test_it_converts(input: &Path,
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -93,7 +94,7 @@ fn strip_headers_list() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -101,7 +102,7 @@ fn strip_headers_list() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -134,7 +135,7 @@ fn strip_headers_safe() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -142,7 +143,7 @@ fn strip_headers_safe() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -175,7 +176,7 @@ fn strip_headers_all() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -183,7 +184,7 @@ fn strip_headers_all() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -216,7 +217,7 @@ fn strip_headers_none() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -224,7 +225,7 @@ fn strip_headers_none() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -255,7 +256,7 @@ fn interlacing_0_to_1() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -263,7 +264,7 @@ fn interlacing_0_to_1() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -292,7 +293,7 @@ fn interlacing_1_to_0() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -300,7 +301,7 @@ fn interlacing_1_to_0() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -331,7 +332,7 @@ fn interlacing_0_to_1_small_files() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -339,7 +340,7 @@ fn interlacing_0_to_1_small_files() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -372,7 +373,7 @@ fn interlacing_1_to_0_small_files() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -380,7 +381,7 @@ fn interlacing_1_to_0_small_files() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -414,7 +415,7 @@ fn interlaced_0_to_1_other_filter_mode() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -422,7 +423,7 @@ fn interlaced_0_to_1_other_filter_mode() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -470,7 +471,7 @@ fn fix_errors() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -478,7 +479,7 @@ fn fix_errors() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -504,7 +505,7 @@ fn issue_42() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -512,7 +513,7 @@ fn issue_42() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use image::Pixel;
|
|||
use oxipng::colors::{BitDepth, ColorType};
|
||||
use oxipng::png;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
use std::fs::remove_file;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -37,7 +38,7 @@ fn test_it_converts(input: &Path,
|
|||
|
||||
match oxipng::optimize(input, opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ fn test_it_converts(input: &Path,
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use image::Pixel;
|
|||
use oxipng::colors::{BitDepth, ColorType};
|
||||
use oxipng::png;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
use std::fs::remove_file;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -37,7 +38,7 @@ fn test_it_converts(input: &Path,
|
|||
|
||||
match oxipng::optimize(input, opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ fn test_it_converts(input: &Path,
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1247,7 +1248,7 @@ fn palette_should_be_reduced_with_dupes() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -1255,7 +1256,7 @@ fn palette_should_be_reduced_with_dupes() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(&output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1287,7 +1288,7 @@ fn palette_should_be_reduced_with_unused() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -1295,7 +1296,7 @@ fn palette_should_be_reduced_with_unused() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(&output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1327,7 +1328,7 @@ fn palette_should_be_reduced_with_both() {
|
|||
|
||||
match oxipng::optimize(&input, &opts) {
|
||||
Ok(_) => (),
|
||||
Err(x) => panic!(x.to_owned()),
|
||||
Err(x) => panic!(x.description().to_owned()),
|
||||
};
|
||||
assert!(output.exists());
|
||||
|
||||
|
|
@ -1335,7 +1336,7 @@ fn palette_should_be_reduced_with_both() {
|
|||
Ok(x) => x,
|
||||
Err(x) => {
|
||||
remove_file(&output).ok();
|
||||
panic!(x.to_owned())
|
||||
panic!(x.description().to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue