Skip to content

Commit 3806fd2

Browse files
Merge pull request #2677 from SixLabors/js/fix-2268
Use a smarter approach to determine the transparent index when encoding palette Pngs.
2 parents 0cbf475 + 624277b commit 3806fd2

File tree

5 files changed

+45
-1
lines changed

5 files changed

+45
-1
lines changed

src/ImageSharp/Formats/Png/PngEncoderCore.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Buffers;
55
using System.Buffers.Binary;
6+
using System.Numerics;
67
using System.Runtime.CompilerServices;
78
using System.Runtime.InteropServices;
89
using SixLabors.ImageSharp.Common.Helpers;
@@ -1527,7 +1528,24 @@ private void SanitizeAndSetEncoderOptions<TPixel>(
15271528
{
15281529
// We can use the color data from the decoded metadata here.
15291530
// We avoid dithering by default to preserve the original colors.
1530-
this.derivedTransparencyIndex = metadata.ColorTable.Value.Span.IndexOf(Color.Transparent);
1531+
ReadOnlySpan<Color> palette = metadata.ColorTable.Value.Span;
1532+
1533+
// Certain operations perform alpha premultiplication, which can cause the color to change so we
1534+
// must search for the transparency index in the palette.
1535+
// Transparent pixels are much more likely to be found at the end of a palette.
1536+
int index = -1;
1537+
for (int i = palette.Length - 1; i >= 0; i--)
1538+
{
1539+
Vector4 instance = palette[i].ToScaledVector4();
1540+
if (instance.W == 0f)
1541+
{
1542+
index = i;
1543+
break;
1544+
}
1545+
}
1546+
1547+
this.derivedTransparencyIndex = index;
1548+
15311549
this.quantizer = new PaletteQuantizer(metadata.ColorTable.Value, new() { Dither = null }, this.derivedTransparencyIndex);
15321550
}
15331551
else

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using SixLabors.ImageSharp.Formats.Webp;
99
using SixLabors.ImageSharp.Metadata;
1010
using SixLabors.ImageSharp.PixelFormats;
11+
using SixLabors.ImageSharp.Processing;
1112
using SixLabors.ImageSharp.Processing.Processors.Quantization;
1213
using SixLabors.ImageSharp.Tests.TestUtilities;
1314
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
@@ -678,6 +679,22 @@ public void Issue2469_Quantized_Encode_Artifacts<TPixel>(TestImageProvider<TPixe
678679
encoded.CompareToReferenceOutput(ImageComparer.Exact, provider);
679680
}
680681

682+
// https://github.com/SixLabors/ImageSharp/issues/2469
683+
[Theory]
684+
[WithFile(TestImages.Png.Issue2668, PixelTypes.Rgba32)]
685+
public void Issue2668_Quantized_Encode_Alpha<TPixel>(TestImageProvider<TPixel> provider)
686+
where TPixel : unmanaged, IPixel<TPixel>
687+
{
688+
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance);
689+
image.Mutate(x => x.Resize(100, 100));
690+
691+
PngEncoder encoder = new() { BitDepth = PngBitDepth.Bit8, ColorType = PngColorType.Palette };
692+
693+
string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder);
694+
using Image<Rgba32> encoded = Image.Load<Rgba32>(actualOutputFile);
695+
encoded.CompareToReferenceOutput(ImageComparer.Exact, provider);
696+
}
697+
681698
private static void TestPngEncoderCore<TPixel>(
682699
TestImageProvider<TPixel> provider,
683700
PngColorType pngColorType,

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ public static class Png
151151
// Issue 2447: https://github.com/SixLabors/ImageSharp/issues/2447
152152
public const string Issue2447 = "Png/issues/issue_2447.png";
153153

154+
// Issue 2668: https://github.com/SixLabors/ImageSharp/issues/2668
155+
public const string Issue2668 = "Png/issues/Issue_2668.png";
156+
154157
public static class Bad
155158
{
156159
public const string MissingDataChunk = "Png/xdtn0g01.png";
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)