Fix clippy lints and run rustfmt
This commit is contained in:
parent
041c433ccb
commit
1305b5cf17
8 changed files with 147 additions and 95 deletions
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
37
src/lib.rs
37
src/lib.rs
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue