Skip to content

Commit

Permalink
Fix handling gif encoding for global palettes. (#2614)
Browse files Browse the repository at this point in the history
* Handle global ani with 256 palette and no trans

* Bump diff for windows
  • Loading branch information
JimBobSquarePants committed Dec 11, 2023
1 parent 6863127 commit ad1b0e6
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 9 deletions.
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.

0 comments on commit ad1b0e6

Please sign in to comment.