Fix clippy lints and run rustfmt

This commit is contained in:
Joshua Holmer 2018-11-26 13:41:14 -05:00
parent 041c433ccb
commit 1305b5cf17
8 changed files with 147 additions and 95 deletions

View file

@ -260,9 +260,7 @@ fn reductions_alpha_black(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgba_8_reduce_alpha_black.png"));
let png = PngData::new(&input, false).unwrap();
b.iter(|| {
png.reduced_alpha_channel(AlphaOptim::Black)
});
b.iter(|| png.reduced_alpha_channel(AlphaOptim::Black));
}
#[bench]
@ -270,9 +268,7 @@ fn reductions_alpha_white(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgba_8_reduce_alpha_white.png"));
let png = PngData::new(&input, false).unwrap();
b.iter(|| {
png.reduced_alpha_channel(AlphaOptim::White)
});
b.iter(|| png.reduced_alpha_channel(AlphaOptim::White));
}
#[bench]
@ -280,9 +276,7 @@ fn reductions_alpha_left(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgba_8_reduce_alpha_left.png"));
let png = PngData::new(&input, false).unwrap();
b.iter(|| {
png.reduced_alpha_channel(AlphaOptim::Left)
});
b.iter(|| png.reduced_alpha_channel(AlphaOptim::Left));
}
#[bench]
@ -290,9 +284,7 @@ fn reductions_alpha_right(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgba_8_reduce_alpha_right.png"));
let png = PngData::new(&input, false).unwrap();
b.iter(|| {
png.reduced_alpha_channel(AlphaOptim::Right)
});
b.iter(|| png.reduced_alpha_channel(AlphaOptim::Right));
}
#[bench]
@ -300,9 +292,7 @@ fn reductions_alpha_up(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgba_8_reduce_alpha_up.png"));
let png = PngData::new(&input, false).unwrap();
b.iter(|| {
png.reduced_alpha_channel(AlphaOptim::Up)
});
b.iter(|| png.reduced_alpha_channel(AlphaOptim::Up));
}
#[bench]
@ -310,7 +300,5 @@ fn reductions_alpha_down(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgba_8_reduce_alpha_down.png"));
let png = PngData::new(&input, false).unwrap();
b.iter(|| {
png.reduced_alpha_channel(AlphaOptim::Down)
});
b.iter(|| png.reduced_alpha_channel(AlphaOptim::Down));
}

View file

@ -1,8 +1,8 @@
use atomicmin::AtomicMin;
use PngResult;
use PngError;
use cloudflare_zlib::*;
pub use cloudflare_zlib::is_supported;
use cloudflare_zlib::*;
use PngError;
use PngResult;
impl From<ZError> for PngError {
fn from(err: ZError) -> Self {
@ -21,14 +21,14 @@ pub fn cfzlib_deflate(
max_size: &AtomicMin,
) -> PngResult<Vec<u8>> {
let mut stream = Deflate::new(level.into(), strategy.into(), window_bits.into())?;
stream.reserve(max_size.get().unwrap_or(data.len()/2));
stream.reserve(max_size.get().unwrap_or(data.len() / 2));
let max_size = max_size.as_atomic_usize();
// max size is generally checked after each split,
// so splitting the buffer into pieces gices more checks
// = better chance of hitting it sooner.
let (first, rest) = data.split_at(data.len()/2);
let (first, rest) = data.split_at(data.len() / 2);
stream.compress_with_limit(first, max_size)?;
let (rest1, rest2) = rest.split_at(rest.len()/2);
let (rest1, rest2) = rest.split_at(rest.len() / 2);
stream.compress_with_limit(rest1, max_size)?;
stream.compress_with_limit(rest2, max_size)?;
Ok(stream.finish()?)
@ -36,7 +36,13 @@ pub fn cfzlib_deflate(
#[test]
fn compress_test() {
let vec = cfzlib_deflate(b"azxcvbnm", Z_BEST_COMPRESSION as u8, Z_DEFAULT_STRATEGY as u8, 15, &AtomicMin::new(None)).unwrap();
let vec = cfzlib_deflate(
b"azxcvbnm",
Z_BEST_COMPRESSION as u8,
Z_DEFAULT_STRATEGY as u8,
15,
&AtomicMin::new(None),
).unwrap();
let res = ::deflate::inflate(&vec).unwrap();
assert_eq!(&res, b"azxcvbnm");
}

View file

@ -93,8 +93,11 @@ pub fn deinterlace_image(png: &mut PngData) {
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 - u32::from(pass_constants.x_shift) + u32::from(pass_constants.x_step) - 1)
/ u32::from(pass_constants.x_step)) as usize * bits_per_pixel as usize;
let bits_in_line = ((png.ihdr_data.width - u32::from(pass_constants.x_shift)
+ u32::from(pass_constants.x_step)
- 1)
/ u32::from(pass_constants.x_step)) 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 {

View file

@ -4,19 +4,19 @@ extern crate byteorder;
extern crate cloudflare_zlib;
extern crate crc;
extern crate image;
extern crate rgb;
extern crate itertools;
extern crate miniz_oxide;
extern crate num_cpus;
#[cfg(feature = "parallel")]
extern crate rayon;
extern crate rgb;
extern crate zopfli;
use atomicmin::AtomicMin;
use crc::crc32;
use deflate::inflate;
use image::{DynamicImage, GenericImageView, ImageFormat, Pixel};
use png::PngData;
use deflate::inflate;
use crc::crc32;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use std::collections::{HashMap, HashSet};
@ -867,8 +867,11 @@ fn perform_strip(png: &mut PngData, opts: &Options) {
if png.aux_headers.get(b"sRGB").is_some() {
// Files aren't supposed to have both chunks, so we chose to honor sRGB
png.aux_headers.remove(b"iCCP");
} else if let Some(intent) = png.aux_headers.get(b"iCCP")
.and_then(|iccp| srgb_rendering_intent(iccp)) {
} else if let Some(intent) = png
.aux_headers
.get(b"iCCP")
.and_then(|iccp| srgb_rendering_intent(iccp))
{
// sRGB-like profile can be safely replaced with
// an sRGB chunk with the same rendering intent
png.aux_headers.remove(b"iCCP");
@ -883,7 +886,9 @@ fn srgb_rendering_intent(mut iccp: &[u8]) -> Option<u8> {
loop {
let (&n, rest) = iccp.split_first()?;
iccp = rest;
if n == 0 {break;}
if n == 0 {
break;
}
}
let (&compression_method, compressed_data) = iccp.split_first()?;
@ -898,21 +903,21 @@ fn srgb_rendering_intent(mut iccp: &[u8]) -> Option<u8> {
// The Profile ID header of ICC has a fixed layout,
// and is supposed to contain MD5 of profile data at this offset
match icc_data.get(84..100)? {
b"\x29\xf8\x3d\xde\xaf\xf2\x55\xae\x78\x42\xfa\xe4\xca\x83\x39\x0d" |
b"\xc9\x5b\xd6\x37\xe9\x5d\x8a\x3b\x0d\xf3\x8f\x99\xc1\x32\x03\x89" |
b"\xfc\x66\x33\x78\x37\xe2\x88\x6b\xfd\x72\xe9\x83\x82\x28\xf1\xb8" |
b"\x34\x56\x2a\xbf\x99\x4c\xcd\x06\x6d\x2c\x57\x21\xd0\xd6\x8c\x5d" => {
b"\x29\xf8\x3d\xde\xaf\xf2\x55\xae\x78\x42\xfa\xe4\xca\x83\x39\x0d"
| b"\xc9\x5b\xd6\x37\xe9\x5d\x8a\x3b\x0d\xf3\x8f\x99\xc1\x32\x03\x89"
| b"\xfc\x66\x33\x78\x37\xe2\x88\x6b\xfd\x72\xe9\x83\x82\x28\xf1\xb8"
| b"\x34\x56\x2a\xbf\x99\x4c\xcd\x06\x6d\x2c\x57\x21\xd0\xd6\x8c\x5d" => {
Some(rendering_intent)
},
}
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" => {
// Known-bad profiles are identified by their CRC
match (crc32::checksum_ieee(&icc_data), icc_data.len()) {
(0x5d5129ce, 3024) |
(0x182ea552, 3144) |
(0xf29e526d, 3144) => Some(rendering_intent),
_ => None,
(0x5d51_29ce, 3024) | (0x182e_a552, 3144) | (0xf29e_526d, 3144) => {
Some(rendering_intent)
}
_ => None,
}
},
}
_ => None,
}
}

View file

@ -1,6 +1,3 @@
use std::collections::hash_map::Entry::*;
use rgb::RGBA8;
use rgb::ComponentSlice;
use atomicmin::AtomicMin;
use byteorder::{BigEndian, WriteBytesExt};
use colors::{AlphaOptim, BitDepth, ColorType};
@ -15,6 +12,9 @@ use itertools::flatten;
use rayon::prelude::*;
use reduction::bit_depth::*;
use reduction::color::*;
use rgb::ComponentSlice;
use rgb::RGBA8;
use std::collections::hash_map::Entry::*;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
@ -49,6 +49,8 @@ pub struct PngData {
pub aux_headers: HashMap<[u8; 4], Vec<u8>>,
}
type PaletteWithTrns = (Option<Vec<RGBA8>>, Option<Vec<u8>>);
impl PngData {
/// Create a new `PngData` struct by opening a file
#[inline]
@ -116,7 +118,11 @@ impl PngData {
let ihdr_header = parse_ihdr_header(&ihdr)?;
let raw_data = deflate::inflate(idat_headers.as_ref())?;
let (palette, transparency_pixel) = Self::palette_to_rgba(ihdr_header.color_type, aux_headers.remove(b"PLTE"), aux_headers.remove(b"tRNS"))?;
let (palette, transparency_pixel) = Self::palette_to_rgba(
ihdr_header.color_type,
aux_headers.remove(b"PLTE"),
aux_headers.remove(b"tRNS"),
)?;
let mut png_data = Self {
idat_data: idat_headers,
@ -132,10 +138,16 @@ impl PngData {
}
/// Handle transparency header
fn palette_to_rgba(color_type: ColorType, palette_data: Option<Vec<u8>>, trns_data: Option<Vec<u8>>) -> Result<(Option<Vec<RGBA8>>, Option<Vec<u8>>), PngError> {
fn palette_to_rgba(
color_type: ColorType,
palette_data: Option<Vec<u8>>,
trns_data: Option<Vec<u8>>,
) -> Result<PaletteWithTrns, PngError> {
if color_type == ColorType::Indexed {
let palette_data = palette_data.ok_or_else(|| PngError::new("no palette in indexed image"))?;
let mut palette: Vec<_> = palette_data.chunks(3)
let palette_data =
palette_data.ok_or_else(|| PngError::new("no palette in indexed image"))?;
let mut palette: Vec<_> = palette_data
.chunks(3)
.map(|color| RGBA8::new(color[0], color[1], color[2], 255))
.collect();
@ -189,14 +201,22 @@ impl PngData {
}
// Palette
if let Some(ref palette) = self.palette {
let mut palette_data = Vec::with_capacity(palette.len()*3);
let mut palette_data = Vec::with_capacity(palette.len() * 3);
for px in palette {
palette_data.extend_from_slice(px.rgb().as_slice());
}
write_png_block(b"PLTE", &palette_data, &mut output);
let num_transparent = palette.iter().enumerate().fold(0, |prev, (index, px)| {
if px.a != 255 {index+1} else {prev}
});
let num_transparent =
palette.iter().enumerate().fold(
0,
|prev, (index, px)| {
if px.a != 255 {
index + 1
} else {
prev
}
},
);
if num_transparent > 0 {
let trns_data: Vec<_> = palette[0..num_transparent].iter().map(|px| px.a).collect();
write_png_block(b"tRNS", &trns_data, &mut output);
@ -389,21 +409,26 @@ impl PngData {
let mut next_index = 0;
let mut seen = HashMap::with_capacity(palette.len());
for (i, (used, palette_map)) in used.iter().cloned().zip(palette_map.iter_mut()).enumerate() {
for (i, (used, palette_map)) in
used.iter().cloned().zip(palette_map.iter_mut()).enumerate()
{
if !used {
continue;
}
// There are invalid files that use pixel indices beyond palette size
let color = palette.get(i).cloned().unwrap_or(RGBA8::new(0,0,0,255));
let color = palette
.get(i)
.cloned()
.unwrap_or_else(|| RGBA8::new(0, 0, 0, 255));
match seen.entry(color) {
Vacant(new) => {
*palette_map = next_index;
new.insert(next_index);
next_index += 1;
},
}
Occupied(remap_to) => {
*palette_map = *remap_to.get();
},
}
}
}
if (0..palette.len()).all(|i| palette_map[i] == i as u8) {
@ -421,14 +446,14 @@ impl PngData {
// low bit-depths can be pre-computed for every byte value
match self.ihdr_data.bit_depth {
BitDepth::Four => for byte in 0..=255 {
byte_map[byte as usize] = palette_map[(byte & 0x0F) as usize] |
(palette_map[(byte >> 4) as usize] << 4);
byte_map[byte as usize] =
palette_map[(byte & 0x0F) as usize] | (palette_map[(byte >> 4) as usize] << 4);
},
BitDepth::Two => for byte in 0..=255 {
byte_map[byte as usize] = palette_map[(byte & 0x03) as usize] |
(palette_map[((byte >> 2) & 0x03) as usize] << 2) |
(palette_map[((byte >> 4) & 0x03) as usize] << 4) |
(palette_map[((byte >> 6)) as usize] << 6);
byte_map[byte as usize] = palette_map[(byte & 0x03) as usize]
| (palette_map[((byte >> 2) & 0x03) as usize] << 2)
| (palette_map[((byte >> 4) & 0x03) as usize] << 4)
| (palette_map[(byte >> 6) as usize] << 6);
},
_ => {}
}
@ -443,8 +468,11 @@ impl PngData {
self.transparency_pixel = None;
if let Some(palette) = self.palette.take() {
let max_index = palette_map.iter().max().cloned().unwrap_or(0) as usize;
let mut new_palette = vec![RGBA8::new(0,0,0,255); max_index+1];
for (color, (map_to, used)) in palette.into_iter().zip(palette_map.iter().cloned().zip(used.iter().cloned())) {
let mut new_palette = vec![RGBA8::new(0, 0, 0, 255); max_index + 1];
for (color, (map_to, used)) in palette
.into_iter()
.zip(palette_map.iter().cloned().zip(used.iter().cloned()))
{
if used {
new_palette[map_to as usize] = color;
}

View file

@ -25,11 +25,7 @@ impl<'a> Iterator for ScanLines<'a> {
let (data, rest) = self.raw_data.split_at(len);
self.raw_data = rest;
let (&filter, data) = data.split_first().unwrap();
ScanLine {
filter,
data,
pass,
}
ScanLine { filter, data, pass }
})
}
}
@ -60,11 +56,7 @@ impl<'a> Iterator for ScanLinesMut<'a> {
let (data, rest) = tmp.split_at_mut(len);
self.raw_data = Some(rest);
let (&mut filter, data) = data.split_first_mut().unwrap();
ScanLineMut {
filter,
data,
pass,
}
ScanLineMut { filter, data, pass }
})
}
}
@ -87,7 +79,11 @@ impl ScanLineRanges {
width: png.ihdr_data.width,
height: png.ihdr_data.height,
left: png.raw_data.len(),
pass: if png.ihdr_data.interlaced == 1 {Some((1, 0))} else {None},
pass: if png.ihdr_data.interlaced == 1 {
Some((1, 0))
} else {
None
},
}
}
}
@ -154,7 +150,7 @@ impl Iterator for ScanLineRanges {
// Standard, non-interlaced PNG scanlines
(self.width, None)
};
let bits_per_line = pixels_per_line * self.bits_per_pixel as u32;
let bits_per_line = pixels_per_line * u32::from(self.bits_per_pixel);
let bytes_per_line = ((bits_per_line + 7) / 8) as usize;
let len = bytes_per_line + 1;
self.left -= len;
@ -173,7 +169,6 @@ pub struct ScanLine<'a> {
pub pass: Option<u8>,
}
#[derive(Debug)]
/// A scan line in a PNG image
pub struct ScanLineMut<'a> {

View file

@ -1,9 +1,9 @@
use std::hash::Hash;
use rgb::{RGBA8, RGB8, FromSlice};
use colors::{BitDepth, ColorType};
use itertools::Itertools;
use png::PngData;
use rgb::{FromSlice, RGB8, RGBA8};
use std::collections::HashMap;
use std::hash::Hash;
use super::alpha::reduce_alpha_channel;
@ -74,8 +74,14 @@ pub fn reduce_rgba_to_grayscale_alpha(png: &mut PngData) -> bool {
true
}
fn reduce_scanline_to_palette<T>(iter: impl IntoIterator<Item=T>, palette: &mut HashMap<T, u8>, reduced: &mut Vec<u8>) -> bool
where T: Eq + Hash {
fn reduce_scanline_to_palette<T>(
iter: impl IntoIterator<Item = T>,
palette: &mut HashMap<T, u8>,
reduced: &mut Vec<u8>,
) -> bool
where
T: Eq + Hash,
{
for pixel in iter {
let idx = if let Some(&idx) = palette.get(&pixel) {
idx
@ -99,28 +105,49 @@ pub fn reduce_color_to_palette(png: &mut PngData) -> bool {
}
let mut reduced = Vec::with_capacity(png.raw_data.len());
let mut palette = HashMap::with_capacity(257);
let transparency_pixel = png.transparency_pixel.as_ref().map(|t| RGB8::new(t[1], t[3], t[5]));
let transparency_pixel = png
.transparency_pixel
.as_ref()
.map(|t| RGB8::new(t[1], t[3], t[5]));
for line in png.scan_lines() {
reduced.push(line.filter);
let ok = if png.ihdr_data.color_type == ColorType::RGB {
reduce_scanline_to_palette(line.data.as_rgb().iter().cloned().map(|px| {
px.alpha(if Some(px) != transparency_pixel {255} else {0})
}), &mut palette, &mut reduced)
reduce_scanline_to_palette(
line.data.as_rgb().iter().cloned().map(|px| {
px.alpha(if Some(px) != transparency_pixel {
255
} else {
0
})
}),
&mut palette,
&mut reduced,
)
} else {
debug_assert_eq!(png.ihdr_data.color_type, ColorType::RGBA);
reduce_scanline_to_palette(line.data.as_rgba().iter().cloned(), &mut palette, &mut reduced)
reduce_scanline_to_palette(
line.data.as_rgba().iter().cloned(),
&mut palette,
&mut reduced,
)
};
if !ok {
return false;
}
}
let num_transparent = palette.iter()
.filter_map(|(px, &idx)| if px.a != 255 {Some(idx as usize +1)} else {None})
.max();
let trns_size = num_transparent.map(|n| n+8).unwrap_or(0);
let num_transparent = palette
.iter()
.filter_map(|(px, &idx)| {
if px.a != 255 {
Some(idx as usize + 1)
} else {
None
}
}).max();
let trns_size = num_transparent.map(|n| n + 8).unwrap_or(0);
let headers_size = palette.len()*3 + 8 + trns_size;
let headers_size = palette.len() * 3 + 8 + trns_size;
if reduced.len() + headers_size > png.raw_data.len() {
// Reduction would result in a larger image
return false;
@ -147,7 +174,7 @@ pub fn reduce_color_to_palette(png: &mut PngData) -> bool {
sbit_header.pop();
}
let mut palette_vec = vec![RGBA8::new(0,0,0,0); palette.len()];
let mut palette_vec = vec![RGBA8::new(0, 0, 0, 0); palette.len()];
for (color, idx) in palette {
palette_vec[idx as usize] = color;
}

View file

@ -1,7 +1,7 @@
extern crate oxipng;
use oxipng::OutFile;
use oxipng::Headers;
use oxipng::OutFile;
use std::default::Default;
use std::fs;
use std::fs::File;