Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling gif encoding for global palettes. #2614

Merged
merged 2 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/ImageSharp/Formats/Gif/GifEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,14 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
{
// We avoid dithering by default to preserve the original colors.
int transparencyIndex = GetTransparentIndex(quantized, frameMetadata);
this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex);
if (transparencyIndex >= 0 || gifMetadata.GlobalColorTable.Value.Length < 256)
{
this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex);
}
else
{
this.quantizer = KnownQuantizers.Octree;
}
}
else
{
Expand Down Expand Up @@ -198,19 +205,17 @@ private static GifMetadata GetGifMetadata<TPixel>(Image<TPixel> image)
private static GifFrameMetadata GetGifFrameMetadata<TPixel>(ImageFrame<TPixel> frame, int transparencyIndex)
where TPixel : unmanaged, IPixel<TPixel>
{
GifFrameMetadata? metadata = null;
if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif))
{
return (GifFrameMetadata)gif.DeepClone();
metadata = (GifFrameMetadata)gif.DeepClone();
}

GifFrameMetadata? metadata = null;
if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png))
else if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png))
{
AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata();
metadata = GifFrameMetadata.FromAnimatedMetadata(ani);
}

if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp))
else if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp))
{
AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata();
metadata = GifFrameMetadata.FromAnimatedMetadata(ani);
Expand Down
3 changes: 3 additions & 0 deletions src/ImageSharp/Formats/Gif/MetadataExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this Gif
// has a local palette with 256 colors and is not transparent we should use 'Source'.
bool blendSource = source.DisposalMethod == GifDisposalMethod.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency);

// If the color table is global and frame has no transparency. Consider it 'Source' also.
blendSource |= source.ColorTableMode == GifColorTableMode.Global && !source.HasTransparency;

return new()
{
ColorTable = source.LocalColorTable,
Expand Down
2 changes: 1 addition & 1 deletion tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ public void Encode_AnimatedFormatTransform_FromGif<TPixel>(TestImageProvider<TPi
// TODO: Find a better way to compare.
// The image has been visually checked but the quantization pattern used in the png encoder
// means we cannot use an exact comparison nor replicate using the quantizing processor.
ImageComparer.TolerantPercentage(0.46f).VerifySimilarity(output, image);
ImageComparer.TolerantPercentage(0.613f).VerifySimilarity(output, image);

GifMetadata gif = image.Metadata.GetGifMetadata();
PngMetadata png = output.Metadata.GetPngMetadata();
Expand Down
4 changes: 3 additions & 1 deletion tests/ImageSharp.Tests/TestImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ public static class Gif
public const string MixedDisposal = "Gif/mixed-disposal.gif";
public const string M4nb = "Gif/m4nb.gif";
public const string Bit18RGBCube = "Gif/18-bit_RGB_Cube.gif";
public const string Global256NoTrans = "Gif/global-256-no-trans.gif";

// Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite
public const string ZeroSize = "Gif/image-zero-size.gif";
Expand Down Expand Up @@ -535,7 +536,8 @@ public static class Issues
Issues.Issue2450_B,
Issues.BadDescriptorWidth,
Issues.Issue1530,
Bit18RGBCube
Bit18RGBCube,
Global256NoTrans
};
}

Expand Down
3 changes: 3 additions & 0 deletions tests/Images/Input/Gif/global-256-no-trans.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading