Apply clippy fixes
This commit is contained in:
parent
868fd502b9
commit
f862a0df24
10 changed files with 99 additions and 93 deletions
|
|
@ -25,7 +25,8 @@ impl AtomicMin {
|
||||||
let mut current_val = self.val.load(Relaxed);
|
let mut current_val = self.val.load(Relaxed);
|
||||||
loop {
|
loop {
|
||||||
if new_val < current_val {
|
if new_val < current_val {
|
||||||
if let Err(v) = self.val
|
if let Err(v) = self
|
||||||
|
.val
|
||||||
.compare_exchange(current_val, new_val, SeqCst, Relaxed)
|
.compare_exchange(current_val, new_val, SeqCst, Relaxed)
|
||||||
{
|
{
|
||||||
current_val = v;
|
current_val = v;
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ impl fmt::Display for ColorType {
|
||||||
impl ColorType {
|
impl ColorType {
|
||||||
/// Get the code used by the PNG specification to denote this color type
|
/// Get the code used by the PNG specification to denote this color type
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn png_header_code(&self) -> u8 {
|
pub fn png_header_code(self) -> u8 {
|
||||||
match *self {
|
match self {
|
||||||
ColorType::Grayscale => 0,
|
ColorType::Grayscale => 0,
|
||||||
ColorType::RGB => 2,
|
ColorType::RGB => 2,
|
||||||
ColorType::Indexed => 3,
|
ColorType::Indexed => 3,
|
||||||
|
|
@ -46,8 +46,8 @@ impl ColorType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn channels_per_pixel(&self) -> u8 {
|
pub fn channels_per_pixel(self) -> u8 {
|
||||||
match *self {
|
match self {
|
||||||
ColorType::Grayscale | ColorType::Indexed => 1,
|
ColorType::Grayscale | ColorType::Indexed => 1,
|
||||||
ColorType::GrayscaleAlpha => 2,
|
ColorType::GrayscaleAlpha => 2,
|
||||||
ColorType::RGB => 3,
|
ColorType::RGB => 3,
|
||||||
|
|
@ -91,8 +91,8 @@ impl fmt::Display for BitDepth {
|
||||||
impl BitDepth {
|
impl BitDepth {
|
||||||
/// Retrieve the number of bits per channel per pixel as a `u8`
|
/// Retrieve the number of bits per channel per pixel as a `u8`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_u8(&self) -> u8 {
|
pub fn as_u8(self) -> u8 {
|
||||||
match *self {
|
match self {
|
||||||
BitDepth::One => 1,
|
BitDepth::One => 1,
|
||||||
BitDepth::Two => 2,
|
BitDepth::Two => 2,
|
||||||
BitDepth::Four => 4,
|
BitDepth::Four => 4,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use atomicmin::AtomicMin;
|
use atomicmin::AtomicMin;
|
||||||
use error::PngError;
|
use error::PngError;
|
||||||
use miniz_oxide::deflate::core::*;
|
use miniz_oxide::deflate::core::*;
|
||||||
|
use PngResult;
|
||||||
|
|
||||||
pub fn compress_to_vec_oxipng(
|
pub fn compress_to_vec_oxipng(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
|
|
@ -8,7 +9,7 @@ pub fn compress_to_vec_oxipng(
|
||||||
window_bits: i32,
|
window_bits: i32,
|
||||||
strategy: i32,
|
strategy: i32,
|
||||||
max_size: &AtomicMin,
|
max_size: &AtomicMin,
|
||||||
) -> Result<Vec<u8>, PngError> {
|
) -> PngResult<Vec<u8>> {
|
||||||
// The comp flags function sets the zlib flag if the window_bits parameter is > 0.
|
// The comp flags function sets the zlib flag if the window_bits parameter is > 0.
|
||||||
let flags = create_comp_flags_from_zip_params(level.into(), window_bits, strategy);
|
let flags = create_comp_flags_from_zip_params(level.into(), window_bits, strategy);
|
||||||
let mut compressor = CompressorOxide::new(flags);
|
let mut compressor = CompressorOxide::new(flags);
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,19 @@ use error::PngError;
|
||||||
use miniz_oxide;
|
use miniz_oxide;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use zopfli;
|
use zopfli;
|
||||||
|
use PngResult;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod miniz_stream;
|
pub mod miniz_stream;
|
||||||
|
|
||||||
/// Decompress a data stream using the DEFLATE algorithm
|
/// Decompress a data stream using the DEFLATE algorithm
|
||||||
pub fn inflate(data: &[u8]) -> Result<Vec<u8>, PngError> {
|
pub fn inflate(data: &[u8]) -> PngResult<Vec<u8>> {
|
||||||
miniz_oxide::inflate::decompress_to_vec_zlib(data)
|
miniz_oxide::inflate::decompress_to_vec_zlib(data)
|
||||||
.map_err(|e| PngError::new(&format!("Error on decompress: {:?}", e)))
|
.map_err(|e| PngError::new(&format!("Error on decompress: {:?}", e)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compress a data stream using the DEFLATE algorithm
|
/// Compress a data stream using the DEFLATE algorithm
|
||||||
pub fn deflate(
|
pub fn deflate(data: &[u8], zc: u8, zs: u8, zw: u8, max_size: &AtomicMin) -> PngResult<Vec<u8>> {
|
||||||
data: &[u8],
|
|
||||||
zc: u8,
|
|
||||||
zs: u8,
|
|
||||||
zw: u8,
|
|
||||||
max_size: &AtomicMin,
|
|
||||||
) -> Result<Vec<u8>, PngError> {
|
|
||||||
#[cfg(feature = "cfzlib")]
|
#[cfg(feature = "cfzlib")]
|
||||||
{
|
{
|
||||||
if is_cfzlib_supported() {
|
if is_cfzlib_supported() {
|
||||||
|
|
@ -55,7 +50,7 @@ pub fn cfzlib_deflate(
|
||||||
strategy: u8,
|
strategy: u8,
|
||||||
window_bits: u8,
|
window_bits: u8,
|
||||||
max_size: &AtomicMin,
|
max_size: &AtomicMin,
|
||||||
) -> Result<Vec<u8>, PngError> {
|
) -> PngResult<Vec<u8>> {
|
||||||
use cloudflare_zlib_sys::*;
|
use cloudflare_zlib_sys::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
|
@ -98,7 +93,7 @@ pub fn cfzlib_deflate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zopfli_deflate(data: &[u8]) -> Result<Vec<u8>, PngError> {
|
pub fn zopfli_deflate(data: &[u8]) -> PngResult<Vec<u8>> {
|
||||||
let mut output = Vec::with_capacity(max(1024, data.len() / 20));
|
let mut output = Vec::with_capacity(max(1024, data.len() / 20));
|
||||||
let options = zopfli::Options::default();
|
let options = zopfli::Options::default();
|
||||||
match zopfli::compress(&options, &zopfli::Format::Zlib, data, &mut output) {
|
match zopfli::compress(&options, &zopfli::Format::Zlib, data, &mut output) {
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,8 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> Vec
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
filtered.push(match i.checked_sub(bpp) {
|
filtered.push(match i.checked_sub(bpp) {
|
||||||
Some(x) => byte.wrapping_sub(
|
Some(x) => byte
|
||||||
((u16::from(data[x]) + u16::from(last_line[i])) >> 1) as u8,
|
.wrapping_sub(((u16::from(data[x]) + u16::from(last_line[i])) >> 1) as u8),
|
||||||
),
|
|
||||||
None => byte.wrapping_sub(last_line[i] >> 1),
|
None => byte.wrapping_sub(last_line[i] >> 1),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -87,31 +86,33 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
3 => for (i, byte) in data.iter().enumerate() {
|
3 => {
|
||||||
if last_line.is_empty() {
|
for (i, byte) in data.iter().enumerate() {
|
||||||
match i.checked_sub(bpp) {
|
if last_line.is_empty() {
|
||||||
Some(x) => {
|
match i.checked_sub(bpp) {
|
||||||
let b = unfiltered[x];
|
Some(x) => {
|
||||||
unfiltered.push(byte.wrapping_add(b >> 1));
|
let b = unfiltered[x];
|
||||||
}
|
unfiltered.push(byte.wrapping_add(b >> 1));
|
||||||
None => {
|
}
|
||||||
unfiltered.push(*byte);
|
None => {
|
||||||
}
|
unfiltered.push(*byte);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
match i.checked_sub(bpp) {
|
||||||
|
Some(x) => {
|
||||||
|
let b = unfiltered[x];
|
||||||
|
unfiltered.push(byte.wrapping_add(
|
||||||
|
((u16::from(b) + u16::from(last_line[i])) >> 1) as u8,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
unfiltered.push(byte.wrapping_add(last_line[i] >> 1));
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
} else {
|
}
|
||||||
match i.checked_sub(bpp) {
|
}
|
||||||
Some(x) => {
|
|
||||||
let b = unfiltered[x];
|
|
||||||
unfiltered.push(byte.wrapping_add(
|
|
||||||
((u16::from(b) + u16::from(last_line[i])) >> 1) as u8,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
unfiltered.push(byte.wrapping_add(last_line[i] >> 1));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
},
|
|
||||||
4 => for (i, byte) in data.iter().enumerate() {
|
4 => for (i, byte) in data.iter().enumerate() {
|
||||||
if last_line.is_empty() {
|
if last_line.is_empty() {
|
||||||
match i.checked_sub(bpp) {
|
match i.checked_sub(bpp) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use crc::crc32;
|
||||||
use error::PngError;
|
use error::PngError;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use PngResult;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
/// Headers from the IHDR chunk of the image
|
/// Headers from the IHDR chunk of the image
|
||||||
|
|
@ -46,14 +47,22 @@ pub fn file_header_is_valid(bytes: &[u8]) -> bool {
|
||||||
*bytes == expected_header
|
*bytes == expected_header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct RawHeader<'a> {
|
||||||
|
pub name: &'a [u8],
|
||||||
|
pub data: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_next_header<'a>(
|
pub fn parse_next_header<'a>(
|
||||||
byte_data: &'a [u8],
|
byte_data: &'a [u8],
|
||||||
byte_offset: &mut usize,
|
byte_offset: &mut usize,
|
||||||
fix_errors: bool,
|
fix_errors: bool,
|
||||||
) -> Result<Option<(&'a [u8], &'a [u8])>, PngError> {
|
) -> PngResult<Option<RawHeader<'a>>> {
|
||||||
let mut rdr = Cursor::new(byte_data
|
let mut rdr = Cursor::new(
|
||||||
.get(*byte_offset..*byte_offset + 4)
|
byte_data
|
||||||
.ok_or(PngError::TruncatedData)?);
|
.get(*byte_offset..*byte_offset + 4)
|
||||||
|
.ok_or(PngError::TruncatedData)?,
|
||||||
|
);
|
||||||
let length = rdr.read_u32::<BigEndian>().unwrap();
|
let length = rdr.read_u32::<BigEndian>().unwrap();
|
||||||
*byte_offset += 4;
|
*byte_offset += 4;
|
||||||
|
|
||||||
|
|
@ -71,9 +80,11 @@ pub fn parse_next_header<'a>(
|
||||||
.get(*byte_offset..*byte_offset + length as usize)
|
.get(*byte_offset..*byte_offset + length as usize)
|
||||||
.ok_or(PngError::TruncatedData)?;
|
.ok_or(PngError::TruncatedData)?;
|
||||||
*byte_offset += length as usize;
|
*byte_offset += length as usize;
|
||||||
let mut rdr = Cursor::new(byte_data
|
let mut rdr = Cursor::new(
|
||||||
.get(*byte_offset..*byte_offset + 4)
|
byte_data
|
||||||
.ok_or(PngError::TruncatedData)?);
|
.get(*byte_offset..*byte_offset + 4)
|
||||||
|
.ok_or(PngError::TruncatedData)?,
|
||||||
|
);
|
||||||
let crc = rdr.read_u32::<BigEndian>().unwrap();
|
let crc = rdr.read_u32::<BigEndian>().unwrap();
|
||||||
*byte_offset += 4;
|
*byte_offset += 4;
|
||||||
|
|
||||||
|
|
@ -87,10 +98,13 @@ pub fn parse_next_header<'a>(
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some((chunk_name, data)))
|
Ok(Some(RawHeader {
|
||||||
|
name: chunk_name,
|
||||||
|
data,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, PngError> {
|
pub fn parse_ihdr_header(byte_data: &[u8]) -> PngResult<IhdrData> {
|
||||||
let mut rdr = Cursor::new(&byte_data[0..8]);
|
let mut rdr = Cursor::new(&byte_data[0..8]);
|
||||||
Ok(IhdrData {
|
Ok(IhdrData {
|
||||||
color_type: match byte_data[9] {
|
color_type: match byte_data[9] {
|
||||||
|
|
|
||||||
25
src/lib.rs
25
src/lib.rs
|
|
@ -21,7 +21,7 @@ use std::fmt;
|
||||||
use std::fs::{copy, File};
|
use std::fs::{copy, File};
|
||||||
use std::io::{stdin, stdout, BufWriter, Read, Write};
|
use std::io::{stdin, stdout, BufWriter, Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Mutex;
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
pub use colors::AlphaOptim;
|
pub use colors::AlphaOptim;
|
||||||
|
|
@ -96,6 +96,8 @@ impl<T: Into<PathBuf>> From<T> for InFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type PngResult<T> = Result<T, PngError>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// Options controlling the output of the `optimize` function
|
/// Options controlling the output of the `optimize` function
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
|
|
@ -321,7 +323,7 @@ impl Default for Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform optimization on the input file using the options provided
|
/// Perform optimization on the input file using the options provided
|
||||||
pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> Result<(), PngError> {
|
pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<()> {
|
||||||
// Initialize the thread pool with correct number of threads
|
// Initialize the thread pool with correct number of threads
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
let thread_count = opts.threads;
|
let thread_count = opts.threads;
|
||||||
|
|
@ -418,7 +420,7 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> Result<(),
|
||||||
|
|
||||||
/// Perform optimization on the input file using the options provided, where the file is already
|
/// Perform optimization on the input file using the options provided, where the file is already
|
||||||
/// loaded in-memory
|
/// loaded in-memory
|
||||||
pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result<Vec<u8>, PngError> {
|
pub fn optimize_from_memory(data: &[u8], opts: &Options) -> PngResult<Vec<u8>> {
|
||||||
// Initialize the thread pool with correct number of threads
|
// Initialize the thread pool with correct number of threads
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
let thread_count = opts.threads;
|
let thread_count = opts.threads;
|
||||||
|
|
@ -454,11 +456,7 @@ struct TrialOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform optimization on the input PNG object using the options provided
|
/// Perform optimization on the input PNG object using the options provided
|
||||||
fn optimize_png(
|
fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options) -> PngResult<Vec<u8>> {
|
||||||
png: &mut PngData,
|
|
||||||
original_data: &[u8],
|
|
||||||
opts: &Options,
|
|
||||||
) -> Result<Vec<u8>, PngError> {
|
|
||||||
type TrialWithData = (TrialOptions, Vec<u8>);
|
type TrialWithData = (TrialOptions, Vec<u8>);
|
||||||
|
|
||||||
let deadline = Deadline::new(opts);
|
let deadline = Deadline::new(opts);
|
||||||
|
|
@ -771,7 +769,7 @@ fn perform_reductions(png: &mut PngData, opts: &Options, deadline: &Deadline) ->
|
||||||
struct Deadline {
|
struct Deadline {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
print_message: Mutex<bool>,
|
print_message: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deadline {
|
impl Deadline {
|
||||||
|
|
@ -779,7 +777,7 @@ impl Deadline {
|
||||||
Self {
|
Self {
|
||||||
start: Instant::now(),
|
start: Instant::now(),
|
||||||
timeout: opts.timeout,
|
timeout: opts.timeout,
|
||||||
print_message: Mutex::new(opts.verbosity.is_some()),
|
print_message: AtomicBool::new(opts.verbosity.is_some()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -789,9 +787,8 @@ impl Deadline {
|
||||||
pub fn passed(&self) -> bool {
|
pub fn passed(&self) -> bool {
|
||||||
if let Some(timeout) = self.timeout {
|
if let Some(timeout) = self.timeout {
|
||||||
if self.start.elapsed() > timeout {
|
if self.start.elapsed() > timeout {
|
||||||
let mut print_message = self.print_message.lock().unwrap();
|
if self.print_message.load(Ordering::Relaxed) {
|
||||||
if *print_message {
|
self.print_message.store(false, Ordering::Relaxed);
|
||||||
*print_message = false;
|
|
||||||
eprintln!("Timed out after {} second(s)", timeout.as_secs());
|
eprintln!("Timed out after {} second(s)", timeout.as_secs());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -852,7 +849,7 @@ fn is_fully_optimized(original_size: usize, optimized_size: usize, opts: &Option
|
||||||
original_size <= optimized_size && !opts.force && opts.interlace.is_none()
|
original_size <= optimized_size && !opts.force && opts.interlace.is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_backup(input_path: &Path) -> Result<(), PngError> {
|
fn perform_backup(input_path: &Path) -> PngResult<()> {
|
||||||
let backup_file = input_path.with_extension(format!(
|
let backup_file = input_path.with_extension(format!(
|
||||||
"bak.{}",
|
"bak.{}",
|
||||||
input_path.extension().unwrap().to_str().unwrap()
|
input_path.extension().unwrap().to_str().unwrap()
|
||||||
|
|
|
||||||
13
src/main.rs
13
src/main.rs
|
|
@ -9,8 +9,9 @@ use clap::{App, AppSettings, Arg, ArgMatches};
|
||||||
use oxipng::AlphaOptim;
|
use oxipng::AlphaOptim;
|
||||||
use oxipng::Deflaters;
|
use oxipng::Deflaters;
|
||||||
use oxipng::Headers;
|
use oxipng::Headers;
|
||||||
|
use oxipng::Options;
|
||||||
|
use oxipng::PngResult;
|
||||||
use oxipng::{InFile, OutFile};
|
use oxipng::{InFile, OutFile};
|
||||||
use oxipng::{Options, PngError};
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs::DirBuilder;
|
use std::fs::DirBuilder;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
@ -240,7 +241,7 @@ fn main() {
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
let res: Result<(), PngError> = files
|
let res: PngResult<()> = files
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(input, output)| oxipng::optimize(&input, &output, &opts))
|
.map(|(input, output)| oxipng::optimize(&input, &output, &opts))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
@ -321,7 +322,8 @@ fn parse_opts_into_struct(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(x) = matches.value_of("timeout") {
|
if let Some(x) = matches.value_of("timeout") {
|
||||||
let num = x.parse()
|
let num = x
|
||||||
|
.parse()
|
||||||
.map_err(|_| "Timeout must be a number".to_owned())?;
|
.map_err(|_| "Timeout must be a number".to_owned())?;
|
||||||
opts.timeout = Some(Duration::from_secs(num));
|
opts.timeout = Some(Duration::from_secs(num));
|
||||||
}
|
}
|
||||||
|
|
@ -435,7 +437,8 @@ fn parse_opts_into_struct(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(hdrs) = matches.value_of("strip") {
|
if let Some(hdrs) = matches.value_of("strip") {
|
||||||
let hdrs = hdrs.split(',')
|
let hdrs = hdrs
|
||||||
|
.split(',')
|
||||||
.map(|x| x.trim().to_owned())
|
.map(|x| x.trim().to_owned())
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
if hdrs.contains(&"safe".to_owned()) || hdrs.contains(&"all".to_owned()) {
|
if hdrs.contains(&"safe".to_owned()) || hdrs.contains(&"all".to_owned()) {
|
||||||
|
|
@ -525,5 +528,5 @@ fn parse_numeric_range_opts(
|
||||||
return Ok(items);
|
return Ok(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(ERROR_MESSAGE.to_owned());
|
Err(ERROR_MESSAGE.to_owned())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,19 +95,14 @@ impl PngData {
|
||||||
// Read the data headers
|
// Read the data headers
|
||||||
let mut aux_headers: HashMap<String, Vec<u8>> = HashMap::new();
|
let mut aux_headers: HashMap<String, Vec<u8>> = HashMap::new();
|
||||||
let mut idat_headers: Vec<u8> = Vec::new();
|
let mut idat_headers: Vec<u8> = Vec::new();
|
||||||
loop {
|
while let Some(header) = parse_next_header(byte_data, &mut byte_offset, fix_errors)? {
|
||||||
let header = parse_next_header(byte_data, &mut byte_offset, fix_errors)?;
|
match header.name {
|
||||||
let (name, data) = match header {
|
b"IDAT" => idat_headers.extend(header.data),
|
||||||
Some(x) => x,
|
|
||||||
None => break,
|
|
||||||
};
|
|
||||||
match name {
|
|
||||||
b"IDAT" => idat_headers.extend(data),
|
|
||||||
b"acTL" => return Err(PngError::APNGNotSupported),
|
b"acTL" => return Err(PngError::APNGNotSupported),
|
||||||
_ => {
|
_ => {
|
||||||
let name =
|
let name = String::from_utf8(header.name.to_owned())
|
||||||
String::from_utf8(name.to_owned()).map_err(|_| PngError::InvalidData)?;
|
.map_err(|_| PngError::InvalidData)?;
|
||||||
aux_headers.insert(name, data.to_owned());
|
aux_headers.insert(name, header.data.to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +179,8 @@ impl PngData {
|
||||||
let _ = ihdr_data.write_u8(self.ihdr_data.interlaced);
|
let _ = ihdr_data.write_u8(self.ihdr_data.interlaced);
|
||||||
write_png_block(b"IHDR", &ihdr_data, &mut output);
|
write_png_block(b"IHDR", &ihdr_data, &mut output);
|
||||||
// Ancillary headers
|
// Ancillary headers
|
||||||
for (key, header) in self.aux_headers
|
for (key, header) in self
|
||||||
|
.aux_headers
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&(key, _)| !(*key == "bKGD" || *key == "hIST" || *key == "tRNS"))
|
.filter(|&(key, _)| !(*key == "bKGD" || *key == "hIST" || *key == "tRNS"))
|
||||||
{
|
{
|
||||||
|
|
@ -202,7 +198,8 @@ impl PngData {
|
||||||
write_png_block(b"tRNS", transparency_pixel, &mut output);
|
write_png_block(b"tRNS", transparency_pixel, &mut output);
|
||||||
}
|
}
|
||||||
// Special ancillary headers that need to come after PLTE but before IDAT
|
// Special ancillary headers that need to come after PLTE but before IDAT
|
||||||
for (key, header) in self.aux_headers
|
for (key, header) in self
|
||||||
|
.aux_headers
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&(key, _)| *key == "bKGD" || *key == "hIST" || *key == "tRNS")
|
.filter(|&(key, _)| *key == "bKGD" || *key == "hIST" || *key == "tRNS")
|
||||||
{
|
{
|
||||||
|
|
@ -713,12 +710,11 @@ impl PngData {
|
||||||
|
|
||||||
fn reduce_alpha_to_up(&self, bpc: usize, bpp: usize) -> Vec<u8> {
|
fn reduce_alpha_to_up(&self, bpc: usize, bpp: usize) -> Vec<u8> {
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
let mut scan_lines = self.scan_lines()
|
let mut scan_lines = self.scan_lines().collect::<Vec<ScanLine>>();
|
||||||
.collect::<Vec<ScanLine>>();
|
|
||||||
scan_lines.reverse();
|
scan_lines.reverse();
|
||||||
let mut last_line = vec![0; scan_lines[0].data.len()];
|
let mut last_line = vec![0; scan_lines[0].data.len()];
|
||||||
let mut current_line = Vec::with_capacity(last_line.len());
|
let mut current_line = Vec::with_capacity(last_line.len());
|
||||||
for line in scan_lines.into_iter() {
|
for line in scan_lines {
|
||||||
current_line.push(line.filter);
|
current_line.push(line.filter);
|
||||||
for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) {
|
for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) {
|
||||||
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,8 @@ pub fn reduce_alpha_channel(png: &mut PngData, channels: u8) -> Option<Vec<u8>>
|
||||||
let colored_bytes = bpp - byte_depth;
|
let colored_bytes = bpp - byte_depth;
|
||||||
for line in png.scan_lines() {
|
for line in png.scan_lines() {
|
||||||
for (i, &byte) in line.data.iter().enumerate() {
|
for (i, &byte) in line.data.iter().enumerate() {
|
||||||
if i as u8 & bpp_mask >= colored_bytes {
|
if i as u8 & bpp_mask >= colored_bytes && byte != 255 {
|
||||||
if byte != 255 {
|
return None;
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue