Skip to content

Commit ad1b0e6

Browse files
Fix handling gif encoding for global palettes. (#2614)
* Handle global ani with 256 palette and no trans * Bump diff for windows
1 parent 6863127 commit ad1b0e6

File tree

5 files changed

+22
-9
lines changed

5 files changed

+22
-9
lines changed

src/ImageSharp/Formats/Gif/GifEncoderCore.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,14 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
103103
{
104104
// We avoid dithering by default to preserve the original colors.
105105
int transparencyIndex = GetTransparentIndex(quantized, frameMetadata);
106-
this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex);
106+
if (transparencyIndex >= 0 || gifMetadata.GlobalColorTable.Value.Length < 256)
107+
{
108+
this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex);
109+
}
110+
else
111+
{
112+
this.quantizer = KnownQuantizers.Octree;
113+
}
107114
}
108115
else
109116
{
@@ -198,19 +205,17 @@ private static GifMetadata GetGifMetadata<TPixel>(Image<TPixel> image)
198205
private static GifFrameMetadata GetGifFrameMetadata<TPixel>(ImageFrame<TPixel> frame, int transparencyIndex)
199206
where TPixel : unmanaged, IPixel<TPixel>
200207
{
208+
GifFrameMetadata? metadata = null;
201209
if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif))
202210
{
203-
return (GifFrameMetadata)gif.DeepClone();
211+
metadata = (GifFrameMetadata)gif.DeepClone();
204212
}
205-
206-
GifFrameMetadata? metadata = null;
207-
if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png))
213+
else if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png))
208214
{
209215
AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata();
210216
metadata = GifFrameMetadata.FromAnimatedMetadata(ani);
211217
}
212-
213-
if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp))
218+
else if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp))
214219
{
215220
AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata();
216221
metadata = GifFrameMetadata.FromAnimatedMetadata(ani);

src/ImageSharp/Formats/Gif/MetadataExtensions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this Gif
8282
// has a local palette with 256 colors and is not transparent we should use 'Source'.
8383
bool blendSource = source.DisposalMethod == GifDisposalMethod.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency);
8484

85+
// If the color table is global and frame has no transparency. Consider it 'Source' also.
86+
blendSource |= source.ColorTableMode == GifColorTableMode.Global && !source.HasTransparency;
87+
8588
return new()
8689
{
8790
ColorTable = source.LocalColorTable,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ public void Encode_AnimatedFormatTransform_FromGif<TPixel>(TestImageProvider<TPi
499499
// TODO: Find a better way to compare.
500500
// The image has been visually checked but the quantization pattern used in the png encoder
501501
// means we cannot use an exact comparison nor replicate using the quantizing processor.
502-
ImageComparer.TolerantPercentage(0.46f).VerifySimilarity(output, image);
502+
ImageComparer.TolerantPercentage(0.613f).VerifySimilarity(output, image);
503503

504504
GifMetadata gif = image.Metadata.GetGifMetadata();
505505
PngMetadata png = output.Metadata.GetPngMetadata();

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ public static class Gif
488488
public const string MixedDisposal = "Gif/mixed-disposal.gif";
489489
public const string M4nb = "Gif/m4nb.gif";
490490
public const string Bit18RGBCube = "Gif/18-bit_RGB_Cube.gif";
491+
public const string Global256NoTrans = "Gif/global-256-no-trans.gif";
491492

492493
// Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite
493494
public const string ZeroSize = "Gif/image-zero-size.gif";
@@ -535,7 +536,8 @@ public static class Issues
535536
Issues.Issue2450_B,
536537
Issues.BadDescriptorWidth,
537538
Issues.Issue1530,
538-
Bit18RGBCube
539+
Bit18RGBCube,
540+
Global256NoTrans
539541
};
540542
}
541543

Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)