Reduce alpha in palette

This commit is contained in:
Andrew 2022-12-10 21:41:39 +13:00
parent 93d48d64e6
commit e842a0e2f3
3 changed files with 31 additions and 19 deletions

View file

@ -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 input = test::black_box(PathBuf::from("tests/files/rgba_16_should_be_rgb_16.png"));
let png = PngData::new(&input, false).unwrap(); 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] #[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 input = test::black_box(PathBuf::from("tests/files/rgba_8_should_be_rgb_8.png"));
let png = PngData::new(&input, false).unwrap(); 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] #[bench]
@ -98,7 +98,7 @@ fn reductions_rgba_to_grayscale_alpha_16(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, false).unwrap(); 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] #[bench]
@ -108,7 +108,7 @@ fn reductions_rgba_to_grayscale_alpha_8(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, false).unwrap(); 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] #[bench]
@ -118,7 +118,7 @@ fn reductions_rgba_to_grayscale_16(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, false).unwrap(); 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] #[bench]
@ -128,7 +128,7 @@ fn reductions_rgba_to_grayscale_8(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, false).unwrap(); 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] #[bench]
@ -138,7 +138,7 @@ fn reductions_rgb_to_grayscale_16(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, false).unwrap(); 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] #[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 input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_grayscale_8.png"));
let png = PngData::new(&input, false).unwrap(); 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] #[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 input = test::black_box(PathBuf::from("tests/files/rgba_8_should_be_palette_8.png"));
let png = PngData::new(&input, false).unwrap(); 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] #[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 input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_palette_8.png"));
let png = PngData::new(&input, false).unwrap(); 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] #[bench]
@ -172,7 +172,7 @@ fn reductions_palette_duplicate_reduction(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, false).unwrap(); let png = PngData::new(&input, false).unwrap();
b.iter(|| reduced_palette(&png.raw)); b.iter(|| reduced_palette(&png.raw, false));
} }
#[bench] #[bench]
@ -182,7 +182,7 @@ fn reductions_palette_unused_reduction(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, false).unwrap(); let png = PngData::new(&input, false).unwrap();
b.iter(|| reduced_palette(&png.raw)); b.iter(|| reduced_palette(&png.raw, false));
} }
#[bench] #[bench]
@ -192,7 +192,7 @@ fn reductions_palette_full_reduction(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, false).unwrap(); let png = PngData::new(&input, false).unwrap();
b.iter(|| reduced_palette(&png.raw)); b.iter(|| reduced_palette(&png.raw, false));
} }
#[bench] #[bench]

View file

@ -703,7 +703,7 @@ fn perform_reductions(
} }
if opts.palette_reduction { 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); png = Arc::new(reduced);
eval.try_image(png.clone()); eval.try_image(png.clone());
report_reduction(&png); report_reduction(&png);
@ -737,7 +737,9 @@ fn perform_reductions(
} }
if opts.color_type_reduction { 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); png = Arc::new(reduced);
eval.try_image(png.clone()); eval.try_image(png.clone());
report_reduction(&png); report_reduction(&png);

View file

@ -17,7 +17,7 @@ pub(crate) use crate::bit_depth::reduce_bit_depth;
/// Attempt to reduce the number of colors in the palette /// Attempt to reduce the number of colors in the palette
/// Returns `None` if palette hasn't changed /// Returns `None` if palette hasn't changed
pub fn reduced_palette(png: &PngImage) -> Option<PngImage> { pub fn reduced_palette(png: &PngImage, optimize_alpha: bool) -> Option<PngImage> {
if png.ihdr.color_type != ColorType::Indexed { if png.ihdr.color_type != ColorType::Indexed {
// Can't reduce if there is no palette // Can't reduce if there is no palette
return None; return None;
@ -90,10 +90,16 @@ pub fn reduced_palette(png: &PngImage) -> Option<PngImage> {
continue; continue;
} }
// There are invalid files that use pixel indices beyond palette size // There are invalid files that use pixel indices beyond palette size
let color = palette let mut color = palette
.get(i) .get(i)
.cloned() .cloned()
.unwrap_or_else(|| RGBA8::new(0, 0, 0, 255)); .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) { match seen.entry(color) {
Vacant(new) => { Vacant(new) => {
palette_map[i] = Some(next_index as u8); palette_map[i] = Some(next_index as u8);
@ -191,7 +197,11 @@ fn reordered_palette(palette: &[RGBA8], palette_map: &[Option<u8>; 256]) -> Vec<
/// Attempt to reduce the color type of the image /// Attempt to reduce the color type of the image
/// Returns true if the color type was reduced, false otherwise /// Returns true if the color type was reduced, false otherwise
pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option<PngImage> { pub fn reduce_color_type(
png: &PngImage,
grayscale_reduction: bool,
optimize_alpha: bool,
) -> Option<PngImage> {
let mut should_reduce_bit_depth = false; let mut should_reduce_bit_depth = false;
let mut reduced = Cow::Borrowed(png); let mut reduced = Cow::Borrowed(png);
@ -234,7 +244,7 @@ pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option<Pn
//Make sure that palette gets sorted. Ideally, this should be done within reduced_color_to_palette. //Make sure that palette gets sorted. Ideally, this should be done within reduced_color_to_palette.
if should_reduce_bit_depth && reduced.ihdr.color_type == ColorType::Indexed { if should_reduce_bit_depth && reduced.ihdr.color_type == ColorType::Indexed {
if let Some(r) = reduced_palette(&reduced) { if let Some(r) = reduced_palette(&reduced, optimize_alpha) {
reduced = Cow::Owned(r); reduced = Cow::Owned(r);
should_reduce_bit_depth = true; should_reduce_bit_depth = true;
} }