From e842a0e2f3c403328f9381c22e8b7b71b20700d9 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 10 Dec 2022 21:41:39 +1300 Subject: [PATCH] Reduce alpha in palette --- benches/reductions.rs | 26 +++++++++++++------------- src/lib.rs | 6 ++++-- src/reduction/mod.rs | 18 ++++++++++++++---- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/benches/reductions.rs b/benches/reductions.rs index 9c43dd18..774c346a 100644 --- a/benches/reductions.rs +++ b/benches/reductions.rs @@ -80,7 +80,7 @@ fn reductions_rgba_to_rgb_16(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgba_16_should_be_rgb_16.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -88,7 +88,7 @@ fn reductions_rgba_to_rgb_8(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgba_8_should_be_rgb_8.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -98,7 +98,7 @@ fn reductions_rgba_to_grayscale_alpha_16(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -108,7 +108,7 @@ fn reductions_rgba_to_grayscale_alpha_8(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -118,7 +118,7 @@ fn reductions_rgba_to_grayscale_16(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -128,7 +128,7 @@ fn reductions_rgba_to_grayscale_8(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -138,7 +138,7 @@ fn reductions_rgb_to_grayscale_16(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -146,7 +146,7 @@ fn reductions_rgb_to_grayscale_8(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_grayscale_8.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -154,7 +154,7 @@ fn reductions_rgba_to_palette_8(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgba_8_should_be_palette_8.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -162,7 +162,7 @@ fn reductions_rgb_to_palette_8(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_palette_8.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw, true)); + b.iter(|| reduce_color_type(&png.raw, true, false)); } #[bench] @@ -172,7 +172,7 @@ fn reductions_palette_duplicate_reduction(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduced_palette(&png.raw)); + b.iter(|| reduced_palette(&png.raw, false)); } #[bench] @@ -182,7 +182,7 @@ fn reductions_palette_unused_reduction(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduced_palette(&png.raw)); + b.iter(|| reduced_palette(&png.raw, false)); } #[bench] @@ -192,7 +192,7 @@ fn reductions_palette_full_reduction(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduced_palette(&png.raw)); + b.iter(|| reduced_palette(&png.raw, false)); } #[bench] diff --git a/src/lib.rs b/src/lib.rs index a69a528f..46891753 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -703,7 +703,7 @@ fn perform_reductions( } if opts.palette_reduction { - if let Some(reduced) = reduced_palette(&png) { + if let Some(reduced) = reduced_palette(&png, opts.optimize_alpha) { png = Arc::new(reduced); eval.try_image(png.clone()); report_reduction(&png); @@ -737,7 +737,9 @@ fn perform_reductions( } if opts.color_type_reduction { - if let Some(reduced) = reduce_color_type(&png, opts.grayscale_reduction) { + if let Some(reduced) = + reduce_color_type(&png, opts.grayscale_reduction, opts.optimize_alpha) + { png = Arc::new(reduced); eval.try_image(png.clone()); report_reduction(&png); diff --git a/src/reduction/mod.rs b/src/reduction/mod.rs index 31d590b2..9f8273fd 100644 --- a/src/reduction/mod.rs +++ b/src/reduction/mod.rs @@ -17,7 +17,7 @@ pub(crate) use crate::bit_depth::reduce_bit_depth; /// Attempt to reduce the number of colors in the palette /// Returns `None` if palette hasn't changed -pub fn reduced_palette(png: &PngImage) -> Option { +pub fn reduced_palette(png: &PngImage, optimize_alpha: bool) -> Option { if png.ihdr.color_type != ColorType::Indexed { // Can't reduce if there is no palette return None; @@ -90,10 +90,16 @@ pub fn reduced_palette(png: &PngImage) -> Option { continue; } // There are invalid files that use pixel indices beyond palette size - let color = palette + let mut color = palette .get(i) .cloned() .unwrap_or_else(|| RGBA8::new(0, 0, 0, 255)); + // If there are multiple fully transparent entries, reduce them into one + if optimize_alpha && color.a == 0 { + color.r = 0; + color.g = 0; + color.b = 0; + } match seen.entry(color) { Vacant(new) => { palette_map[i] = Some(next_index as u8); @@ -191,7 +197,11 @@ fn reordered_palette(palette: &[RGBA8], palette_map: &[Option; 256]) -> Vec< /// Attempt to reduce the color type of the image /// Returns true if the color type was reduced, false otherwise -pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option { +pub fn reduce_color_type( + png: &PngImage, + grayscale_reduction: bool, + optimize_alpha: bool, +) -> Option { let mut should_reduce_bit_depth = false; let mut reduced = Cow::Borrowed(png); @@ -234,7 +244,7 @@ pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option