Run rustfmt since it updated to v0.8.0.
I don't really like the new changes, but we might as well follow along.
This commit is contained in:
parent
d665c61645
commit
84cf6b09c2
9 changed files with 280 additions and 246 deletions
|
|
@ -13,9 +13,9 @@ fn interlacing_16_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(1);
|
safe_png.change_interlacing(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -24,9 +24,9 @@ fn interlacing_8_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(1);
|
safe_png.change_interlacing(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -35,9 +35,9 @@ fn interlacing_4_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(1);
|
safe_png.change_interlacing(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -46,9 +46,9 @@ fn interlacing_2_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(1);
|
safe_png.change_interlacing(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -57,9 +57,9 @@ fn interlacing_1_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(1);
|
safe_png.change_interlacing(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -68,9 +68,9 @@ fn deinterlacing_16_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(0);
|
safe_png.change_interlacing(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -79,9 +79,9 @@ fn deinterlacing_8_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(0);
|
safe_png.change_interlacing(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -90,9 +90,9 @@ fn deinterlacing_4_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(0);
|
safe_png.change_interlacing(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -101,9 +101,9 @@ fn deinterlacing_2_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(0);
|
safe_png.change_interlacing(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -112,7 +112,7 @@ fn deinterlacing_1_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.change_interlacing(0);
|
safe_png.change_interlacing(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ fn reductions_16_to_8_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_bit_depth();
|
safe_png.reduce_bit_depth();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -24,9 +24,9 @@ fn reductions_8_to_4_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_bit_depth();
|
safe_png.reduce_bit_depth();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -35,9 +35,9 @@ fn reductions_8_to_2_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_bit_depth();
|
safe_png.reduce_bit_depth();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -46,9 +46,9 @@ fn reductions_8_to_1_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_bit_depth();
|
safe_png.reduce_bit_depth();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -57,9 +57,9 @@ fn reductions_4_to_2_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_bit_depth();
|
safe_png.reduce_bit_depth();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -68,9 +68,9 @@ fn reductions_4_to_1_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_bit_depth();
|
safe_png.reduce_bit_depth();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -79,9 +79,9 @@ fn reductions_2_to_1_bits(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_bit_depth();
|
safe_png.reduce_bit_depth();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -90,9 +90,9 @@ fn reductions_rgba_to_rgb_16(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -101,9 +101,9 @@ fn reductions_rgba_to_rgb_8(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -112,9 +112,9 @@ fn reductions_rgba_to_grayscale_alpha_16(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -123,9 +123,9 @@ fn reductions_rgba_to_grayscale_alpha_8(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -134,9 +134,9 @@ fn reductions_rgba_to_grayscale_16(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -145,9 +145,9 @@ fn reductions_rgba_to_grayscale_8(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -156,9 +156,9 @@ fn reductions_rgb_to_grayscale_16(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -167,9 +167,9 @@ fn reductions_rgb_to_grayscale_8(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -178,9 +178,9 @@ fn reductions_rgba_to_palette_8(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -189,9 +189,9 @@ fn reductions_rgb_to_palette_8(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_color_type();
|
safe_png.reduce_color_type();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -200,9 +200,9 @@ fn reductions_palette_duplicate_reduction(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_palette();
|
safe_png.reduce_palette();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -211,9 +211,9 @@ fn reductions_palette_unused_reduction(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_palette();
|
safe_png.reduce_palette();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
@ -222,7 +222,7 @@ fn reductions_palette_full_reduction(b: &mut Bencher) {
|
||||||
let png = png::PngData::new(&input, false).unwrap();
|
let png = png::PngData::new(&input, false).unwrap();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
let mut safe_png = png.clone();
|
||||||
safe_png.reduce_palette();
|
safe_png.reduce_palette();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,33 +7,36 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> Vec
|
||||||
1 => {
|
1 => {
|
||||||
filtered.extend_from_slice(&data[0..bpp]);
|
filtered.extend_from_slice(&data[0..bpp]);
|
||||||
filtered.extend(data.iter()
|
filtered.extend(data.iter()
|
||||||
.skip(bpp)
|
.skip(bpp)
|
||||||
.zip(data.iter())
|
.zip(data.iter())
|
||||||
.map(|(cur, last)| cur.wrapping_sub(*last)));
|
.map(|(cur, last)| cur.wrapping_sub(*last)));
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
if last_line.is_empty() {
|
if last_line.is_empty() {
|
||||||
filtered.extend_from_slice(data);
|
filtered.extend_from_slice(data);
|
||||||
} else {
|
} else {
|
||||||
filtered.extend(data.iter()
|
filtered.extend(data.iter().zip(last_line.iter()).map(|(cur, last)| {
|
||||||
.zip(last_line.iter())
|
cur.wrapping_sub(*last)
|
||||||
.map(|(cur, last)| cur.wrapping_sub(*last)));
|
}));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
for (i, byte) in data.iter().enumerate() {
|
for (i, byte) in data.iter().enumerate() {
|
||||||
if last_line.is_empty() {
|
if last_line.is_empty() {
|
||||||
filtered.push(match i.checked_sub(bpp) {
|
filtered.push(match i.checked_sub(bpp) {
|
||||||
Some(x) => byte.wrapping_sub(data[x] >> 1),
|
Some(x) => byte.wrapping_sub(data[x] >> 1),
|
||||||
None => *byte,
|
None => *byte,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
filtered.push(match i.checked_sub(bpp) {
|
filtered.push(match i.checked_sub(bpp) {
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
byte.wrapping_sub(((data[x] as u16 + last_line[i] as u16) >> 1) as u8)
|
byte.wrapping_sub(((data[x] as u16 +
|
||||||
}
|
last_line[i] as u16) >>
|
||||||
None => byte.wrapping_sub(last_line[i] >> 1),
|
1) as
|
||||||
});
|
u8)
|
||||||
|
}
|
||||||
|
None => byte.wrapping_sub(last_line[i] >> 1),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,16 +44,18 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> Vec
|
||||||
for (i, byte) in data.iter().enumerate() {
|
for (i, byte) in data.iter().enumerate() {
|
||||||
if last_line.is_empty() {
|
if last_line.is_empty() {
|
||||||
filtered.push(match i.checked_sub(bpp) {
|
filtered.push(match i.checked_sub(bpp) {
|
||||||
Some(x) => byte.wrapping_sub(data[x]),
|
Some(x) => byte.wrapping_sub(data[x]),
|
||||||
None => *byte,
|
None => *byte,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
filtered.push(match i.checked_sub(bpp) {
|
filtered.push(match i.checked_sub(bpp) {
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
byte.wrapping_sub(paeth_predictor(data[x], last_line[i], last_line[x]))
|
byte.wrapping_sub(paeth_predictor(data[x],
|
||||||
}
|
last_line[i],
|
||||||
None => byte.wrapping_sub(last_line[i]),
|
last_line[x]))
|
||||||
});
|
}
|
||||||
|
None => byte.wrapping_sub(last_line[i]),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,9 +87,9 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V
|
||||||
if last_line.is_empty() {
|
if last_line.is_empty() {
|
||||||
unfiltered.extend_from_slice(data);
|
unfiltered.extend_from_slice(data);
|
||||||
} else {
|
} else {
|
||||||
unfiltered.extend(data.iter()
|
unfiltered.extend(data.iter().zip(last_line.iter()).map(|(cur, last)| {
|
||||||
.zip(last_line.iter())
|
cur.wrapping_add(*last)
|
||||||
.map(|(cur, last)| cur.wrapping_add(*last)));
|
}));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
|
|
@ -103,7 +108,9 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V
|
||||||
match i.checked_sub(bpp) {
|
match i.checked_sub(bpp) {
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
let b = unfiltered[x];
|
let b = unfiltered[x];
|
||||||
unfiltered.push(byte.wrapping_add(((b as u16 + last_line[i] as u16) >> 1) as u8));
|
unfiltered.push(byte.wrapping_add(((b as u16 + last_line[i] as u16) >>
|
||||||
|
1) as
|
||||||
|
u8));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
unfiltered.push(byte.wrapping_add(last_line[i] >> 1));
|
unfiltered.push(byte.wrapping_add(last_line[i] >> 1));
|
||||||
|
|
|
||||||
|
|
@ -48,17 +48,21 @@ pub fn parse_next_header(byte_data: &[u8],
|
||||||
fix_errors: bool)
|
fix_errors: bool)
|
||||||
-> Result<Option<(String, Vec<u8>)>, PngError> {
|
-> Result<Option<(String, Vec<u8>)>, PngError> {
|
||||||
let mut rdr = Cursor::new(byte_data.iter()
|
let mut rdr = Cursor::new(byte_data.iter()
|
||||||
.skip(*byte_offset)
|
.skip(*byte_offset)
|
||||||
.take(4)
|
.take(4)
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<u8>>());
|
.collect::<Vec<u8>>());
|
||||||
let length: u32 = match rdr.read_u32::<BigEndian>() {
|
let length: u32 = match rdr.read_u32::<BigEndian>() {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
||||||
};
|
};
|
||||||
*byte_offset += 4;
|
*byte_offset += 4;
|
||||||
|
|
||||||
let mut header_bytes: Vec<u8> = byte_data.iter().skip(*byte_offset).take(4).cloned().collect();
|
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()) {
|
let header = match String::from_utf8(header_bytes.clone()) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
||||||
|
|
@ -76,10 +80,10 @@ pub fn parse_next_header(byte_data: &[u8],
|
||||||
.collect();
|
.collect();
|
||||||
*byte_offset += length as usize;
|
*byte_offset += length as usize;
|
||||||
let mut rdr = Cursor::new(byte_data.iter()
|
let mut rdr = Cursor::new(byte_data.iter()
|
||||||
.skip(*byte_offset)
|
.skip(*byte_offset)
|
||||||
.take(4)
|
.take(4)
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<u8>>());
|
.collect::<Vec<u8>>());
|
||||||
let crc: u32 = match rdr.read_u32::<BigEndian>() {
|
let crc: u32 = match rdr.read_u32::<BigEndian>() {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")),
|
||||||
|
|
@ -97,26 +101,26 @@ pub fn parse_next_header(byte_data: &[u8],
|
||||||
pub fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, PngError> {
|
pub fn parse_ihdr_header(byte_data: &[u8]) -> Result<IhdrData, PngError> {
|
||||||
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] {
|
||||||
0 => ColorType::Grayscale,
|
0 => ColorType::Grayscale,
|
||||||
2 => ColorType::RGB,
|
2 => ColorType::RGB,
|
||||||
3 => ColorType::Indexed,
|
3 => ColorType::Indexed,
|
||||||
4 => ColorType::GrayscaleAlpha,
|
4 => ColorType::GrayscaleAlpha,
|
||||||
6 => ColorType::RGBA,
|
6 => ColorType::RGBA,
|
||||||
_ => return Err(PngError::new("Unexpected color type in header")),
|
_ => return Err(PngError::new("Unexpected color type in header")),
|
||||||
},
|
},
|
||||||
bit_depth: match byte_data[8] {
|
bit_depth: match byte_data[8] {
|
||||||
1 => BitDepth::One,
|
1 => BitDepth::One,
|
||||||
2 => BitDepth::Two,
|
2 => BitDepth::Two,
|
||||||
4 => BitDepth::Four,
|
4 => BitDepth::Four,
|
||||||
8 => BitDepth::Eight,
|
8 => BitDepth::Eight,
|
||||||
16 => BitDepth::Sixteen,
|
16 => BitDepth::Sixteen,
|
||||||
_ => return Err(PngError::new("Unexpected bit depth in header")),
|
_ => return Err(PngError::new("Unexpected bit depth in header")),
|
||||||
},
|
},
|
||||||
width: rdr.read_u32::<BigEndian>().unwrap(),
|
width: rdr.read_u32::<BigEndian>().unwrap(),
|
||||||
height: rdr.read_u32::<BigEndian>().unwrap(),
|
height: rdr.read_u32::<BigEndian>().unwrap(),
|
||||||
compression: byte_data[10],
|
compression: byte_data[10],
|
||||||
filter: byte_data[11],
|
filter: byte_data[11],
|
||||||
interlaced: byte_data[12],
|
interlaced: byte_data[12],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ pub fn deinterlace_image(png: &mut PngData) {
|
||||||
let bit_vec = BitVec::from_bytes(&line.data);
|
let bit_vec = BitVec::from_bytes(&line.data);
|
||||||
let bits_in_line = ((png.ihdr_data.width - pass_constants.x_shift as u32) as f32 /
|
let bits_in_line = ((png.ihdr_data.width - pass_constants.x_shift as u32) as f32 /
|
||||||
pass_constants.x_step as f32)
|
pass_constants.x_step as f32)
|
||||||
.ceil() as usize * bits_per_pixel as usize;
|
.ceil() as usize * bits_per_pixel as usize;
|
||||||
for (i, bit) in bit_vec.iter().enumerate() {
|
for (i, bit) in bit_vec.iter().enumerate() {
|
||||||
// Avoid moving padded 0's into new image
|
// Avoid moving padded 0's into new image
|
||||||
if i >= bits_in_line {
|
if i >= bits_in_line {
|
||||||
|
|
|
||||||
94
src/lib.rs
94
src/lib.rs
|
|
@ -346,16 +346,14 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> {
|
||||||
{
|
{
|
||||||
match out_file.metadata() {
|
match out_file.metadata() {
|
||||||
Ok(out_meta) => {
|
Ok(out_meta) => {
|
||||||
let readonly = metadata.permissions()
|
let readonly = metadata.permissions().readonly();
|
||||||
.readonly();
|
out_meta.permissions().set_readonly(readonly);
|
||||||
out_meta.permissions()
|
|
||||||
.set_readonly(readonly);
|
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
if opts.verbosity.is_some() {
|
if opts.verbosity.is_some() {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
"Failed to set permissions on output file")
|
"Failed to set permissions on output file")
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +363,7 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> {
|
||||||
if opts.verbosity.is_some() {
|
if opts.verbosity.is_some() {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
"Failed to read permissions on input file")
|
"Failed to read permissions on input file")
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -438,29 +436,29 @@ fn optimize_png(png: &mut PngData,
|
||||||
" {}x{} pixels, PNG format",
|
" {}x{} pixels, PNG format",
|
||||||
png.ihdr_data.width,
|
png.ihdr_data.width,
|
||||||
png.ihdr_data.height)
|
png.ihdr_data.height)
|
||||||
.ok();
|
.ok();
|
||||||
if let Some(ref palette) = png.palette {
|
if let Some(ref palette) = png.palette {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
" {} bits/pixel, {} colors in palette",
|
" {} bits/pixel, {} colors in palette",
|
||||||
png.ihdr_data.bit_depth,
|
png.ihdr_data.bit_depth,
|
||||||
palette.len() / 3)
|
palette.len() / 3)
|
||||||
.ok();
|
.ok();
|
||||||
} else {
|
} else {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
" {}x{} bits/pixel, {:?}",
|
" {}x{} bits/pixel, {:?}",
|
||||||
png.channels_per_pixel(),
|
png.channels_per_pixel(),
|
||||||
png.ihdr_data.bit_depth,
|
png.ihdr_data.bit_depth,
|
||||||
png.ihdr_data.color_type)
|
png.ihdr_data.color_type)
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
" IDAT size = {} bytes",
|
" IDAT size = {} bytes",
|
||||||
idat_original_size)
|
idat_original_size)
|
||||||
.ok();
|
.ok();
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
" File size = {} bytes",
|
" File size = {} bytes",
|
||||||
file_original_size)
|
file_original_size)
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut filter = opts.filter.clone();
|
let mut filter = opts.filter.clone();
|
||||||
|
|
@ -528,35 +526,36 @@ fn optimize_png(png: &mut PngData,
|
||||||
let original_len = original_png.idat_data.len();
|
let original_len = original_png.idat_data.len();
|
||||||
let added_interlacing = opts.interlace == Some(1) && original_png.ihdr_data.interlaced == 0;
|
let added_interlacing = opts.interlace == Some(1) && original_png.ihdr_data.interlaced == 0;
|
||||||
|
|
||||||
let best: Option<TrialWithData> = results.into_par_iter()
|
let best: Option<TrialWithData> =
|
||||||
.weight_max()
|
results.into_par_iter()
|
||||||
.filter_map(|trial| {
|
.weight_max()
|
||||||
let filtered = &filters[&trial.0];
|
.filter_map(|trial| {
|
||||||
let new_idat = if opts.deflate == Deflaters::Zlib {
|
let filtered = &filters[&trial.0];
|
||||||
deflate::deflate(filtered, trial.1, trial.2, trial.3, opts.window)
|
let new_idat = if opts.deflate == Deflaters::Zlib {
|
||||||
} else {
|
deflate::deflate(filtered, trial.1, trial.2, trial.3, opts.window)
|
||||||
deflate::zopfli_deflate(filtered)
|
} else {
|
||||||
|
deflate::zopfli_deflate(filtered)
|
||||||
|
}
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if opts.verbosity == Some(1) {
|
||||||
|
writeln!(&mut stderr(),
|
||||||
|
" zc = {} zm = {} zs = {} f = {} {} bytes",
|
||||||
|
trial.1,
|
||||||
|
trial.2,
|
||||||
|
trial.3,
|
||||||
|
trial.0,
|
||||||
|
new_idat.len())
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if opts.verbosity == Some(1) {
|
if new_idat.len() < original_len || added_interlacing || opts.force {
|
||||||
writeln!(&mut stderr(),
|
Some((trial.0, trial.1, trial.2, trial.3, new_idat))
|
||||||
" zc = {} zm = {} zs = {} f = {} {} bytes",
|
} else {
|
||||||
trial.1,
|
None
|
||||||
trial.2,
|
}
|
||||||
trial.3,
|
})
|
||||||
trial.0,
|
.reduce_with(|i, j| if i.4.len() <= j.4.len() { i } else { j });
|
||||||
new_idat.len())
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
if new_idat.len() < original_len || added_interlacing || opts.force {
|
|
||||||
Some((trial.0, trial.1, trial.2, trial.3, new_idat))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.reduce_with(|i, j| if i.4.len() <= j.4.len() { i } else { j });
|
|
||||||
|
|
||||||
if let Some(better) = best {
|
if let Some(better) = best {
|
||||||
png.idat_data = better.4;
|
png.idat_data = better.4;
|
||||||
|
|
@ -569,7 +568,7 @@ fn optimize_png(png: &mut PngData,
|
||||||
better.3,
|
better.3,
|
||||||
better.0,
|
better.0,
|
||||||
png.idat_data.len())
|
png.idat_data.len())
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
} else if reduction_occurred {
|
} else if reduction_occurred {
|
||||||
png.reset_from_original(original_png);
|
png.reset_from_original(original_png);
|
||||||
|
|
@ -586,13 +585,13 @@ fn optimize_png(png: &mut PngData,
|
||||||
" IDAT size = {} bytes ({} bytes decrease)",
|
" IDAT size = {} bytes ({} bytes decrease)",
|
||||||
png.idat_data.len(),
|
png.idat_data.len(),
|
||||||
idat_original_size - png.idat_data.len())
|
idat_original_size - png.idat_data.len())
|
||||||
.ok();
|
.ok();
|
||||||
} else {
|
} else {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
" IDAT size = {} bytes ({} bytes increase)",
|
" IDAT size = {} bytes ({} bytes increase)",
|
||||||
png.idat_data.len(),
|
png.idat_data.len(),
|
||||||
png.idat_data.len() - idat_original_size)
|
png.idat_data.len() - idat_original_size)
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
if file_original_size >= output.len() {
|
if file_original_size >= output.len() {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
|
|
@ -601,7 +600,7 @@ fn optimize_png(png: &mut PngData,
|
||||||
file_original_size - output.len(),
|
file_original_size - output.len(),
|
||||||
(file_original_size - output.len()) as f64 / file_original_size as f64 *
|
(file_original_size - output.len()) as f64 / file_original_size as f64 *
|
||||||
100f64)
|
100f64)
|
||||||
.ok();
|
.ok();
|
||||||
} else {
|
} else {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
" file size = {} bytes ({} bytes = {:.2}% increase)",
|
" file size = {} bytes ({} bytes = {:.2}% increase)",
|
||||||
|
|
@ -609,7 +608,7 @@ fn optimize_png(png: &mut PngData,
|
||||||
output.len() - file_original_size,
|
output.len() - file_original_size,
|
||||||
(output.len() - file_original_size) as f64 / file_original_size as f64 *
|
(output.len() - file_original_size) as f64 / file_original_size as f64 *
|
||||||
100f64)
|
100f64)
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -682,14 +681,14 @@ fn report_reduction(png: &png::PngData) {
|
||||||
"Reducing image to {} bits/pixel, {} colors in palette",
|
"Reducing image to {} bits/pixel, {} colors in palette",
|
||||||
png.ihdr_data.bit_depth,
|
png.ihdr_data.bit_depth,
|
||||||
palette.len() / 3)
|
palette.len() / 3)
|
||||||
.ok();
|
.ok();
|
||||||
} else {
|
} else {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
"Reducing image to {}x{} bits/pixel, {}",
|
"Reducing image to {}x{} bits/pixel, {}",
|
||||||
png.channels_per_pixel(),
|
png.channels_per_pixel(),
|
||||||
png.ihdr_data.bit_depth,
|
png.ihdr_data.bit_depth,
|
||||||
png.ihdr_data.color_type)
|
png.ihdr_data.color_type)
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -706,7 +705,10 @@ fn perform_strip(png: &mut png::PngData, opts: &Options) {
|
||||||
Headers::Safe => {
|
Headers::Safe => {
|
||||||
const PRESERVED_HEADERS: [&'static str; 9] = ["cHRM", "gAMA", "iCCP", "sBIT", "sRGB",
|
const PRESERVED_HEADERS: [&'static str; 9] = ["cHRM", "gAMA", "iCCP", "sBIT", "sRGB",
|
||||||
"bKGD", "hIST", "pHYs", "sPLT"];
|
"bKGD", "hIST", "pHYs", "sPLT"];
|
||||||
let hdrs = png.aux_headers.keys().cloned().collect::<Vec<String>>();
|
let hdrs = png.aux_headers
|
||||||
|
.keys()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<String>>();
|
||||||
for hdr in hdrs {
|
for hdr in hdrs {
|
||||||
if !PRESERVED_HEADERS.contains(&hdr.as_ref()) {
|
if !PRESERVED_HEADERS.contains(&hdr.as_ref()) {
|
||||||
png.aux_headers.remove(&hdr);
|
png.aux_headers.remove(&hdr);
|
||||||
|
|
|
||||||
17
src/main.rs
17
src/main.rs
|
|
@ -239,13 +239,16 @@ fn handle_optimization(inputs: Vec<PathBuf>, opts: &Options) {
|
||||||
let mut current_opts = opts.clone();
|
let mut current_opts = opts.clone();
|
||||||
if input.is_dir() {
|
if input.is_dir() {
|
||||||
if current_opts.recursive {
|
if current_opts.recursive {
|
||||||
handle_optimization(input.read_dir().unwrap().map(|x| x.unwrap().path()).collect(),
|
handle_optimization(input.read_dir()
|
||||||
|
.unwrap()
|
||||||
|
.map(|x| x.unwrap().path())
|
||||||
|
.collect(),
|
||||||
¤t_opts)
|
¤t_opts)
|
||||||
} else {
|
} else {
|
||||||
writeln!(&mut stderr(),
|
writeln!(&mut stderr(),
|
||||||
"{} is a directory, skipping",
|
"{} is a directory, skipping",
|
||||||
input.display())
|
input.display())
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -310,9 +313,7 @@ fn parse_opts_into_struct(matches: &ArgMatches) -> Result<Options, String> {
|
||||||
if let Some(x) = matches.value_of("output_dir") {
|
if let Some(x) = matches.value_of("output_dir") {
|
||||||
let path = PathBuf::from(x);
|
let path = PathBuf::from(x);
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
match DirBuilder::new()
|
match DirBuilder::new().recursive(true).create(&path) {
|
||||||
.recursive(true)
|
|
||||||
.create(&path) {
|
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(x) => return Err(format!("Could not create output directory {}", x)),
|
Err(x) => return Err(format!("Could not create output directory {}", x)),
|
||||||
};
|
};
|
||||||
|
|
@ -394,7 +395,7 @@ fn parse_opts_into_struct(matches: &ArgMatches) -> Result<Options, String> {
|
||||||
if hdrs.contains(&"safe".to_owned()) || hdrs.contains(&"all".to_owned()) {
|
if hdrs.contains(&"safe".to_owned()) || hdrs.contains(&"all".to_owned()) {
|
||||||
if hdrs.len() > 1 {
|
if hdrs.len() > 1 {
|
||||||
return Err("'safe' or 'all' presets for --strip should be used by themselves"
|
return Err("'safe' or 'all' presets for --strip should be used by themselves"
|
||||||
.to_owned());
|
.to_owned());
|
||||||
}
|
}
|
||||||
if hdrs[0] == "safe" {
|
if hdrs[0] == "safe" {
|
||||||
opts.strip = Headers::Safe;
|
opts.strip = Headers::Safe;
|
||||||
|
|
@ -437,8 +438,8 @@ fn parse_numeric_range_opts(input: &str,
|
||||||
max_value,
|
max_value,
|
||||||
min_value,
|
min_value,
|
||||||
max_value)
|
max_value)
|
||||||
.as_ref())
|
.as_ref())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut items = HashSet::new();
|
let mut items = HashSet::new();
|
||||||
|
|
||||||
if one_item.is_match(input) {
|
if one_item.is_match(input) {
|
||||||
|
|
|
||||||
80
src/png.rs
80
src/png.rs
|
|
@ -50,7 +50,10 @@ impl<'a> Iterator for ScanLines<'a> {
|
||||||
pass.1 = 0;
|
pass.1 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let bits_per_pixel = self.png.ihdr_data.bit_depth.as_u8() as u32 *
|
let bits_per_pixel = self.png
|
||||||
|
.ihdr_data
|
||||||
|
.bit_depth
|
||||||
|
.as_u8() as u32 *
|
||||||
self.png.channels_per_pixel() as u32;
|
self.png.channels_per_pixel() as u32;
|
||||||
let y_steps;
|
let y_steps;
|
||||||
let pixels_factor;
|
let pixels_factor;
|
||||||
|
|
@ -129,23 +132,26 @@ impl<'a> Iterator for ScanLines<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ScanLine {
|
Some(ScanLine {
|
||||||
filter: self.png.raw_data[self.start],
|
filter: self.png.raw_data[self.start],
|
||||||
data: self.png.raw_data[(self.start + 1)..self.end].to_owned(),
|
data: self.png.raw_data[(self.start + 1)..self.end].to_owned(),
|
||||||
pass: current_pass,
|
pass: current_pass,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// Standard, non-interlaced PNG scanlines
|
// Standard, non-interlaced PNG scanlines
|
||||||
let bits_per_line = self.png.ihdr_data.width as usize *
|
let bits_per_line = self.png.ihdr_data.width as usize *
|
||||||
self.png.ihdr_data.bit_depth.as_u8() as usize *
|
self.png
|
||||||
|
.ihdr_data
|
||||||
|
.bit_depth
|
||||||
|
.as_u8() as usize *
|
||||||
self.png.channels_per_pixel() as usize;
|
self.png.channels_per_pixel() as usize;
|
||||||
let bytes_per_line = (bits_per_line as f32 / 8f32).ceil() as usize;
|
let bytes_per_line = (bits_per_line as f32 / 8f32).ceil() as usize;
|
||||||
self.start = self.end;
|
self.start = self.end;
|
||||||
self.end = self.start + bytes_per_line + 1;
|
self.end = self.start + bytes_per_line + 1;
|
||||||
Some(ScanLine {
|
Some(ScanLine {
|
||||||
filter: self.png.raw_data[self.start],
|
filter: self.png.raw_data[self.start],
|
||||||
data: self.png.raw_data[(self.start + 1)..self.end].to_owned(),
|
data: self.png.raw_data[(self.start + 1)..self.end].to_owned(),
|
||||||
pass: None,
|
pass: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -208,7 +214,10 @@ impl PngData {
|
||||||
pub fn from_slice(byte_data: &[u8], fix_errors: bool) -> Result<PngData, PngError> {
|
pub fn from_slice(byte_data: &[u8], fix_errors: bool) -> Result<PngData, PngError> {
|
||||||
let mut byte_offset: usize = 0;
|
let mut byte_offset: usize = 0;
|
||||||
// Test that png header is valid
|
// Test that png header is valid
|
||||||
let header: Vec<u8> = byte_data.iter().take(8).cloned().collect();
|
let header: Vec<u8> = byte_data.iter()
|
||||||
|
.take(8)
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
if !file_header_is_valid(header.as_ref()) {
|
if !file_header_is_valid(header.as_ref()) {
|
||||||
return Err(PngError::new("Invalid PNG header detected"));
|
return Err(PngError::new("Invalid PNG header detected"));
|
||||||
}
|
}
|
||||||
|
|
@ -316,9 +325,11 @@ impl PngData {
|
||||||
ihdr_data.write_u8(self.ihdr_data.interlaced).ok();
|
ihdr_data.write_u8(self.ihdr_data.interlaced).ok();
|
||||||
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().filter(|&(key, _)| {
|
||||||
.iter()
|
!(*key == "bKGD" ||
|
||||||
.filter(|&(key, _)| !(*key == "bKGD" || *key == "hIST" || *key == "tRNS")) {
|
*key == "hIST" ||
|
||||||
|
*key == "tRNS")
|
||||||
|
}) {
|
||||||
write_png_block(key.as_bytes(), header, &mut output);
|
write_png_block(key.as_bytes(), header, &mut output);
|
||||||
}
|
}
|
||||||
// Palette
|
// Palette
|
||||||
|
|
@ -333,9 +344,10 @@ 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().filter(|&(key, _)| {
|
||||||
.iter()
|
*key == "bKGD" || *key == "hIST" ||
|
||||||
.filter(|&(key, _)| *key == "bKGD" || *key == "hIST" || *key == "tRNS") {
|
*key == "tRNS"
|
||||||
|
}) {
|
||||||
write_png_block(key.as_bytes(), header, &mut output);
|
write_png_block(key.as_bytes(), header, &mut output);
|
||||||
}
|
}
|
||||||
// IDAT data
|
// IDAT data
|
||||||
|
|
@ -362,7 +374,7 @@ impl PngData {
|
||||||
let mut unfiltered = Vec::with_capacity(self.raw_data.len());
|
let mut unfiltered = Vec::with_capacity(self.raw_data.len());
|
||||||
let bpp = (((self.ihdr_data.bit_depth.as_u8() * self.channels_per_pixel()) as f32) /
|
let bpp = (((self.ihdr_data.bit_depth.as_u8() * self.channels_per_pixel()) as f32) /
|
||||||
8f32)
|
8f32)
|
||||||
.ceil() as usize;
|
.ceil() as usize;
|
||||||
let mut last_line: Vec<u8> = Vec::new();
|
let mut last_line: Vec<u8> = Vec::new();
|
||||||
for line in self.scan_lines() {
|
for line in self.scan_lines() {
|
||||||
let unfiltered_line = unfilter_line(line.filter, bpp, &line.data, &last_line);
|
let unfiltered_line = unfilter_line(line.filter, bpp, &line.data, &last_line);
|
||||||
|
|
@ -384,7 +396,7 @@ impl PngData {
|
||||||
let mut filtered = Vec::with_capacity(self.raw_data.len());
|
let mut filtered = Vec::with_capacity(self.raw_data.len());
|
||||||
let bpp = (((self.ihdr_data.bit_depth.as_u8() * self.channels_per_pixel()) as f32) /
|
let bpp = (((self.ihdr_data.bit_depth.as_u8() * self.channels_per_pixel()) as f32) /
|
||||||
8f32)
|
8f32)
|
||||||
.ceil() as usize;
|
.ceil() as usize;
|
||||||
let mut last_line: Vec<u8> = Vec::new();
|
let mut last_line: Vec<u8> = Vec::new();
|
||||||
let mut last_pass: Option<u8> = None;
|
let mut last_pass: Option<u8> = None;
|
||||||
for line in self.scan_lines() {
|
for line in self.scan_lines() {
|
||||||
|
|
@ -413,11 +425,11 @@ impl PngData {
|
||||||
}
|
}
|
||||||
let (best_filter, best_line) = trials.iter()
|
let (best_filter, best_line) = trials.iter()
|
||||||
.min_by_key(|x| {
|
.min_by_key(|x| {
|
||||||
x.1.iter().fold(0u64, |acc, &x| {
|
x.1.iter().fold(0u64, |acc, &x| {
|
||||||
let signed = x as i8;
|
let signed = x as i8;
|
||||||
acc + (signed as i16).abs() as u64
|
acc + (signed as i16).abs() as u64
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
filtered.push(*best_filter);
|
filtered.push(*best_filter);
|
||||||
filtered.extend_from_slice(best_line);
|
filtered.extend_from_slice(best_line);
|
||||||
|
|
@ -444,8 +456,8 @@ impl PngData {
|
||||||
// Reduce from 16 to 8 bits per channel per pixel
|
// Reduce from 16 to 8 bits per channel per pixel
|
||||||
let mut reduced = Vec::with_capacity((self.ihdr_data.width * self.ihdr_data.height *
|
let mut reduced = Vec::with_capacity((self.ihdr_data.width * self.ihdr_data.height *
|
||||||
self.channels_per_pixel() as u32 +
|
self.channels_per_pixel() as u32 +
|
||||||
self.ihdr_data
|
self.ihdr_data.height) as
|
||||||
.height) as usize);
|
usize);
|
||||||
let mut high_byte = 0;
|
let mut high_byte = 0;
|
||||||
|
|
||||||
for line in self.scan_lines() {
|
for line in self.scan_lines() {
|
||||||
|
|
@ -491,21 +503,21 @@ impl PngData {
|
||||||
.chunks(3)
|
.chunks(3)
|
||||||
.zip(trns.iter().chain([255].iter().cycle()))
|
.zip(trns.iter().chain([255].iter().cycle()))
|
||||||
.flat_map(|(pixel, trns)| {
|
.flat_map(|(pixel, trns)| {
|
||||||
let mut pixel = pixel.to_owned();
|
let mut pixel = pixel.to_owned();
|
||||||
pixel.push(*trns);
|
pixel.push(*trns);
|
||||||
pixel
|
pixel
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
self.palette.clone().unwrap()
|
self.palette.clone().unwrap()
|
||||||
};
|
};
|
||||||
let mut indexed_palette: Vec<&[u8]> =
|
let mut indexed_palette: Vec<&[u8]> = palette.chunks(if self.transparency_palette
|
||||||
palette.chunks(if self.transparency_palette.is_some() {
|
.is_some() {
|
||||||
4
|
4
|
||||||
} else {
|
} else {
|
||||||
3
|
3
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
// A map of old indexes to new ones, for any moved
|
// A map of old indexes to new ones, for any moved
|
||||||
let mut index_map: HashMap<u8, u8> = HashMap::new();
|
let mut index_map: HashMap<u8, u8> = HashMap::new();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,11 +136,11 @@ pub fn reduce_rgba_to_palette(png: &mut PngData) -> bool {
|
||||||
|
|
||||||
let mut color_palette = Vec::with_capacity(palette.len() * 3 +
|
let mut color_palette = Vec::with_capacity(palette.len() * 3 +
|
||||||
if png.aux_headers
|
if png.aux_headers
|
||||||
.contains_key(&"bKGD".to_string()) {
|
.contains_key(&"bKGD".to_string()) {
|
||||||
6
|
6
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
});
|
});
|
||||||
let mut trans_palette = Vec::with_capacity(palette.len());
|
let mut trans_palette = Vec::with_capacity(palette.len());
|
||||||
for color in &palette {
|
for color in &palette {
|
||||||
for (i, byte) in color.iter().enumerate() {
|
for (i, byte) in color.iter().enumerate() {
|
||||||
|
|
@ -160,7 +160,11 @@ pub fn reduce_rgba_to_palette(png: &mut PngData) -> bool {
|
||||||
|
|
||||||
if let Some(bkgd_header) = png.aux_headers.get_mut(&"bKGD".to_string()) {
|
if let Some(bkgd_header) = png.aux_headers.get_mut(&"bKGD".to_string()) {
|
||||||
assert_eq!(bkgd_header.len(), 6);
|
assert_eq!(bkgd_header.len(), 6);
|
||||||
let header_pixels = bkgd_header.iter().skip(1).step(2).cloned().collect::<Vec<u8>>();
|
let header_pixels = bkgd_header.iter()
|
||||||
|
.skip(1)
|
||||||
|
.step(2)
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<u8>>();
|
||||||
if let Some(entry) = color_palette.chunks(3).position(|x| x == header_pixels.as_slice()) {
|
if let Some(entry) = color_palette.chunks(3).position(|x| x == header_pixels.as_slice()) {
|
||||||
*bkgd_header = vec![entry as u8];
|
*bkgd_header = vec![entry as u8];
|
||||||
} else if color_palette.len() / 3 == 256 {
|
} else if color_palette.len() / 3 == 256 {
|
||||||
|
|
@ -231,7 +235,11 @@ pub fn reduce_rgb_to_palette(png: &mut PngData) -> bool {
|
||||||
|
|
||||||
if let Some(bkgd_header) = png.aux_headers.get_mut(&"bKGD".to_string()) {
|
if let Some(bkgd_header) = png.aux_headers.get_mut(&"bKGD".to_string()) {
|
||||||
assert_eq!(bkgd_header.len(), 6);
|
assert_eq!(bkgd_header.len(), 6);
|
||||||
let header_pixels = bkgd_header.iter().skip(1).step(2).cloned().collect::<Vec<u8>>();
|
let header_pixels = bkgd_header.iter()
|
||||||
|
.skip(1)
|
||||||
|
.step(2)
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<u8>>();
|
||||||
if let Some(entry) = color_palette.chunks(3).position(|x| x == header_pixels.as_slice()) {
|
if let Some(entry) = color_palette.chunks(3).position(|x| x == header_pixels.as_slice()) {
|
||||||
*bkgd_header = vec![entry as u8];
|
*bkgd_header = vec![entry as u8];
|
||||||
} else if color_palette.len() == 255 {
|
} else if color_palette.len() == 255 {
|
||||||
|
|
@ -269,9 +277,9 @@ pub fn reduce_rgb_to_grayscale(png: &mut PngData) -> bool {
|
||||||
.step(2)
|
.step(2)
|
||||||
.cloned()
|
.cloned()
|
||||||
.zip(cur_pixel.iter()
|
.zip(cur_pixel.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.step(2)
|
.step(2)
|
||||||
.cloned())
|
.cloned())
|
||||||
.unique()
|
.unique()
|
||||||
.collect::<Vec<(u8, u8)>>();
|
.collect::<Vec<(u8, u8)>>();
|
||||||
if pixel_bytes.len() > 1 {
|
if pixel_bytes.len() > 1 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue