From b126b777422400d3695dcb2e5957e8a1b98db557 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 20 May 2023 00:38:22 +1000 Subject: [PATCH] Use background index as fallback during dedup. --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 42 ++++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 90e7a8b1ea..6fe8e83c18 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -135,13 +135,15 @@ internal sealed class GifEncoderCore : IImageEncoderInternals // Write the LSD. image.Frames.RootFrame.Metadata.TryGetGifMetadata(out GifFrameMetadata? frameMetadata); - int index = GetTransparentIndex(quantized, frameMetadata); - if (index == -1) + + int transparentIndex = GetTransparentIndex(quantized, frameMetadata); + byte backgroundIndex = unchecked((byte)transparentIndex); + if (transparentIndex == -1) { - index = gifMetadata.BackgroundColor; + backgroundIndex = gifMetadata.BackgroundColor; } - this.WriteLogicalScreenDescriptor(metadata, image.Width, image.Height, index, useGlobalTable, stream); + this.WriteLogicalScreenDescriptor(metadata, image.Width, image.Height, backgroundIndex, useGlobalTable, stream); if (useGlobalTable) { @@ -158,7 +160,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals this.WriteApplicationExtensions(stream, image.Frames.Count, gifMetadata.RepeatCount, xmpProfile); } - this.EncodeFrames(stream, image, quantized, quantized.Palette.ToArray()); + this.EncodeFrames(stream, image, backgroundIndex, quantized, quantized.Palette.ToArray()); stream.WriteByte(GifConstants.EndIntroducer); } @@ -166,6 +168,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals private void EncodeFrames( Stream stream, Image image, + byte backgroundIndex, IndexedImageFrame quantized, ReadOnlyMemory palette) where TPixel : unmanaged, IPixel @@ -197,7 +200,17 @@ internal sealed class GifEncoderCore : IImageEncoderInternals paletteQuantizer = new(this.configuration, this.quantizer!.Options, palette); } - this.EncodeFrame(stream, frame, i, useLocal, frameMetadata, indices, ref previousQuantized, ref quantized!, ref paletteQuantizer); + this.EncodeFrame( + stream, + frame, + i, + useLocal, + frameMetadata, + indices, + backgroundIndex, + ref previousQuantized, + ref quantized!, + ref paletteQuantizer); // Clean up for the next run. if (quantized != previousQuantized) @@ -222,6 +235,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals bool useLocal, GifFrameMetadata? metadata, Buffer2D indices, + byte backgroundIndex, ref IndexedImageFrame previousQuantized, ref IndexedImageFrame quantized, ref PaletteQuantizer globalPaletteQuantizer) @@ -256,10 +270,16 @@ internal sealed class GifEncoderCore : IImageEncoderInternals quantized = globalPaletteQuantizer.QuantizeFrame(frame, frame.Bounds()); transparencyIndex = GetTransparentIndex(quantized, metadata); + byte replacementIndex = unchecked((byte)transparencyIndex); + if (transparencyIndex == -1) + { + replacementIndex = backgroundIndex; + } + // De-duplicate pixels comparing to the previous frame. // Only global is supported for now as the color palettes as the operation required to compare // and offset the index lookups is too expensive for local palettes. - DeDuplicatePixels(previousQuantized, quantized, indices, transparencyIndex); + DeDuplicatePixels(previousQuantized, quantized, indices, replacementIndex); } this.bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); @@ -290,11 +310,9 @@ internal sealed class GifEncoderCore : IImageEncoderInternals IndexedImageFrame background, IndexedImageFrame source, Buffer2D indices, - int transparencyIndex) + byte replacementIndex) where TPixel : unmanaged, IPixel { - // TODO: This should be the background color if not transparent. - byte replacementIndex = unchecked((byte)transparencyIndex); for (int y = 0; y < background.Height; y++) { ref byte backgroundRowBase = ref MemoryMarshal.GetReference(background.DangerousGetRowSpan(y)); @@ -421,7 +439,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals ImageMetadata metadata, int width, int height, - int backgroundIndex, + byte backgroundIndex, bool useGlobalTable, Stream stream) { @@ -459,7 +477,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals width: (ushort)width, height: (ushort)height, packed: packedValue, - backgroundColorIndex: unchecked((byte)backgroundIndex), + backgroundColorIndex: backgroundIndex, ratio); Span buffer = stackalloc byte[20];