Browse Source

Use background index as fallback during dedup.

pull/2500/head
James Jackson-South 3 years ago
parent
commit
b126b77742
  1. 42
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs

42
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -135,13 +135,15 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
// Write the LSD. // Write the LSD.
image.Frames.RootFrame.Metadata.TryGetGifMetadata(out GifFrameMetadata? frameMetadata); 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) if (useGlobalTable)
{ {
@ -158,7 +160,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
this.WriteApplicationExtensions(stream, image.Frames.Count, gifMetadata.RepeatCount, xmpProfile); 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); stream.WriteByte(GifConstants.EndIntroducer);
} }
@ -166,6 +168,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
private void EncodeFrames<TPixel>( private void EncodeFrames<TPixel>(
Stream stream, Stream stream,
Image<TPixel> image, Image<TPixel> image,
byte backgroundIndex,
IndexedImageFrame<TPixel> quantized, IndexedImageFrame<TPixel> quantized,
ReadOnlyMemory<TPixel> palette) ReadOnlyMemory<TPixel> palette)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
@ -197,7 +200,17 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
paletteQuantizer = new(this.configuration, this.quantizer!.Options, palette); 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. // Clean up for the next run.
if (quantized != previousQuantized) if (quantized != previousQuantized)
@ -222,6 +235,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
bool useLocal, bool useLocal,
GifFrameMetadata? metadata, GifFrameMetadata? metadata,
Buffer2D<byte> indices, Buffer2D<byte> indices,
byte backgroundIndex,
ref IndexedImageFrame<TPixel> previousQuantized, ref IndexedImageFrame<TPixel> previousQuantized,
ref IndexedImageFrame<TPixel> quantized, ref IndexedImageFrame<TPixel> quantized,
ref PaletteQuantizer<TPixel> globalPaletteQuantizer) ref PaletteQuantizer<TPixel> globalPaletteQuantizer)
@ -256,10 +270,16 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
quantized = globalPaletteQuantizer.QuantizeFrame(frame, frame.Bounds()); quantized = globalPaletteQuantizer.QuantizeFrame(frame, frame.Bounds());
transparencyIndex = GetTransparentIndex(quantized, metadata); transparencyIndex = GetTransparentIndex(quantized, metadata);
byte replacementIndex = unchecked((byte)transparencyIndex);
if (transparencyIndex == -1)
{
replacementIndex = backgroundIndex;
}
// De-duplicate pixels comparing to the previous frame. // De-duplicate pixels comparing to the previous frame.
// Only global is supported for now as the color palettes as the operation required to compare // 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. // 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); this.bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length);
@ -290,11 +310,9 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
IndexedImageFrame<TPixel> background, IndexedImageFrame<TPixel> background,
IndexedImageFrame<TPixel> source, IndexedImageFrame<TPixel> source,
Buffer2D<byte> indices, Buffer2D<byte> indices,
int transparencyIndex) byte replacementIndex)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// TODO: This should be the background color if not transparent.
byte replacementIndex = unchecked((byte)transparencyIndex);
for (int y = 0; y < background.Height; y++) for (int y = 0; y < background.Height; y++)
{ {
ref byte backgroundRowBase = ref MemoryMarshal.GetReference(background.DangerousGetRowSpan(y)); ref byte backgroundRowBase = ref MemoryMarshal.GetReference(background.DangerousGetRowSpan(y));
@ -421,7 +439,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
ImageMetadata metadata, ImageMetadata metadata,
int width, int width,
int height, int height,
int backgroundIndex, byte backgroundIndex,
bool useGlobalTable, bool useGlobalTable,
Stream stream) Stream stream)
{ {
@ -459,7 +477,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
width: (ushort)width, width: (ushort)width,
height: (ushort)height, height: (ushort)height,
packed: packedValue, packed: packedValue,
backgroundColorIndex: unchecked((byte)backgroundIndex), backgroundColorIndex: backgroundIndex,
ratio); ratio);
Span<byte> buffer = stackalloc byte[20]; Span<byte> buffer = stackalloc byte[20];

Loading…
Cancel
Save