Skip to content

Commit

Permalink
Use a smarter approach to determine the transparent index
Browse files Browse the repository at this point in the history
  • Loading branch information
JimBobSquarePants committed Feb 26, 2024
1 parent 9c9854d commit 2a54881
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 1 deletion.
20 changes: 19 additions & 1 deletion src/ImageSharp/Formats/Png/PngEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Buffers;
using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
Expand Down Expand Up @@ -1527,7 +1528,24 @@ private void SwapScanlineBuffers()
{
// We can use the color data from the decoded metadata here.
// We avoid dithering by default to preserve the original colors.
this.derivedTransparencyIndex = metadata.ColorTable.Value.Span.IndexOf(Color.Transparent);
ReadOnlySpan<Color> palette = metadata.ColorTable.Value.Span;

// Certain operations perform alpha premultiplication, which can cause the color to change so we
// must search for the transparency index in the palette.
// Transparent pixels are much more likely to be found at the end of a palette.
int index = -1;
for (int i = palette.Length - 1; i >= 0; i--)
{
Vector4 instance = palette[i].ToScaledVector4();
if (instance.W == 0f)
{
index = i;
break;
}
}

this.derivedTransparencyIndex = index;

this.quantizer = new PaletteQuantizer(metadata.ColorTable.Value, new() { Dither = null }, this.derivedTransparencyIndex);
}
else
Expand Down
17 changes: 17 additions & 0 deletions tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
Expand Down Expand Up @@ -678,6 +679,22 @@ public void Issue2469_Quantized_Encode_Artifacts<TPixel>(TestImageProvider<TPixe
encoded.CompareToReferenceOutput(ImageComparer.Exact, provider);
}

// https://github.com/SixLabors/ImageSharp/issues/2469
[Theory]
[WithFile(TestImages.Png.Issue2668, PixelTypes.Rgba32)]
public void Issue2668_Quantized_Encode_Alpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance);
image.Mutate(x => x.Resize(100, 100));

PngEncoder encoder = new() { BitDepth = PngBitDepth.Bit8, ColorType = PngColorType.Palette };

string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder);
using Image<Rgba32> encoded = Image.Load<Rgba32>(actualOutputFile);
encoded.CompareToReferenceOutput(ImageComparer.Exact, provider);
}

private static void TestPngEncoderCore<TPixel>(
TestImageProvider<TPixel> provider,
PngColorType pngColorType,
Expand Down
3 changes: 3 additions & 0 deletions tests/ImageSharp.Tests/TestImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ public static class Png
// Issue 2447: https://github.com/SixLabors/ImageSharp/issues/2447
public const string Issue2447 = "Png/issues/issue_2447.png";

// Issue 2668: https://github.com/SixLabors/ImageSharp/issues/2668
public const string Issue2668 = "Png/issues/issue_2668.png";

public static class Bad
{
public const string MissingDataChunk = "Png/xdtn0g01.png";
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions tests/Images/Input/Png/issues/Issue_2668.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2a54881

Please sign in to comment.