Skip to content

Commit

Permalink
Improve indexed to grayscale conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
andrews05 committed Jan 29, 2025
1 parent bbde68d commit 336741b
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 5 deletions.
2 changes: 1 addition & 1 deletion benches/reductions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ fn reductions_palette_8_to_grayscale_8(b: &mut Bencher) {
));
let png = PngData::new(&input, &Options::default()).unwrap();

b.iter(|| color::indexed_to_channels(&png.raw, true));
b.iter(|| color::indexed_to_channels(&png.raw, true, false));
}

#[bench]
Expand Down
21 changes: 18 additions & 3 deletions src/reduction/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,30 @@ pub fn reduced_rgb_to_grayscale(png: &PngImage) -> Option<PngImage> {

/// Attempt to convert indexed to a different color type, returning the resulting image if successful
#[must_use]
pub fn indexed_to_channels(png: &PngImage, allow_grayscale: bool) -> Option<PngImage> {
pub fn indexed_to_channels(
png: &PngImage,
allow_grayscale: bool,
optimize_alpha: bool,
) -> Option<PngImage> {
if png.ihdr.bit_depth != BitDepth::Eight {
return None;
}
let palette = match &png.ihdr.color_type {
ColorType::Indexed { palette } => palette,
let mut palette = match &png.ihdr.color_type {
ColorType::Indexed { palette } => palette.clone(),
_ => return None,
};

// Ensure fully transparent colors are black, which can help with grayscale conversion
if optimize_alpha {
for color in &mut palette {
if color.a == 0 {
color.r = 0;
color.g = 0;
color.b = 0;
}
}
}

// Determine which channels are required
let is_gray = if allow_grayscale {
palette.iter().all(|c| c.r == c.g && c.g == c.b)
Expand Down
4 changes: 3 additions & 1 deletion src/reduction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ pub(crate) fn perform_reductions(
// Attempt to convert from indexed to channels
// This may give a better result due to dropping the PLTE chunk
if !cheap && opts.color_type_reduction && !deadline.passed() {
if let Some(reduced) = indexed_to_channels(&png, opts.grayscale_reduction) {
if let Some(reduced) =
indexed_to_channels(&png, opts.grayscale_reduction, opts.optimize_alpha)
{
// This result should not be passed on to subsequent reductions
eval.try_image(Arc::new(reduced));
evaluation_added = true;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions tests/reduction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,18 @@ fn palette_8_should_be_grayscale_8() {
);
}

#[test]
fn palette_2_should_be_grayscale_alpha_8() {
test_it_converts(
"tests/files/palette_2_should_be_grayscale_alpha_8.png",
true,
INDEXED,
BitDepth::Two,
GRAYSCALE_ALPHA,
BitDepth::Eight,
);
}

#[test]
fn palette_8_should_be_rgb() {
test_it_converts(
Expand Down

0 comments on commit 336741b

Please sign in to comment.