Browse Source

Use a smarter approach to determine the transparent index

pull/2677/head
James Jackson-South 2 years ago
parent
commit
2a548818ac
  1. 20
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  2. 17
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
  3. 3
      tests/ImageSharp.Tests/TestImages.cs
  4. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png
  5. 3
      tests/Images/Input/Png/issues/Issue_2668.png

20
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -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;
@ -1527,7 +1528,24 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
{
// 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

17
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Formats.Png;
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;
@ -678,6 +679,22 @@ public partial class PngEncoderTests
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,

3
tests/ImageSharp.Tests/TestImages.cs

@ -151,6 +151,9 @@ public static class TestImages
// 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";

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f934af128b85b9e8f557d71ac8b1f1473a0922d0754fc0c4ece0d0e3d8d94c39
size 7702

3
tests/Images/Input/Png/issues/Issue_2668.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e8e5b2b933fd8fefd161f1d22970cb60247fd2d93b6c07b8b9ee1fdbc2241a3c
size 390225
Loading…
Cancel
Save