Skip to content

Commit

Permalink
Merge pull request #1980 from SixLabors/js/fix-1962
Browse files Browse the repository at this point in the history
Handle missing global color table.
  • Loading branch information
JimBobSquarePants authored Feb 7, 2022
2 parents 6d434ea + 438a97b commit 5d6f389
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 7 deletions.
39 changes: 32 additions & 7 deletions src/ImageSharp/Formats/Gif/GifDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,17 @@ private void ReadFrame<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> p
indices = this.Configuration.MemoryAllocator.Allocate2D<byte>(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);

this.ReadFrameIndices(indices);
ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>((localColorTable ?? this.globalColorTable).GetSpan());
Span<byte> rawColorTable = default;
if (localColorTable != null)
{
rawColorTable = localColorTable.GetSpan();
}
else if (this.globalColorTable != null)
{
rawColorTable = this.globalColorTable.GetSpan();
}

ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>(rawColorTable);
this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor);

// Skip any remaining blocks
Expand Down Expand Up @@ -415,15 +425,23 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPi
{
int imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.logicalScreenDescriptor.Height;
bool transFlag = this.graphicsControlExtension.TransparencyFlag;

ImageFrame<TPixel> prevFrame = null;
ImageFrame<TPixel> currentFrame = null;
ImageFrame<TPixel> imageFrame;

if (previousFrame is null)
{
// This initializes the image to become fully transparent because the alpha channel is zero.
image = new Image<TPixel>(this.Configuration, imageWidth, imageHeight, this.metadata);
if (!transFlag)
{
image = new Image<TPixel>(this.Configuration, imageWidth, imageHeight, Color.Black.ToPixel<TPixel>(), this.metadata);
}
else
{
// This initializes the image to become fully transparent because the alpha channel is zero.
image = new Image<TPixel>(this.Configuration, imageWidth, imageHeight, this.metadata);
}

this.SetFrameMetadata(image.Frames.RootFrame.Metadata);

Expand All @@ -445,14 +463,18 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPi
this.RestoreToBackground(imageFrame);
}

if (colorTable.Length == 0)
{
return;
}

int interlacePass = 0; // The interlace pass
int interlaceIncrement = 8; // The interlacing line increment
int interlaceY = 0; // The current interlaced line
int descriptorTop = descriptor.Top;
int descriptorBottom = descriptorTop + descriptor.Height;
int descriptorLeft = descriptor.Left;
int descriptorRight = descriptorLeft + descriptor.Width;
bool transFlag = this.graphicsControlExtension.TransparencyFlag;
byte transIndex = this.graphicsControlExtension.TransparencyIndex;
int colorTableMaxIdx = colorTable.Length - 1;

Expand Down Expand Up @@ -635,10 +657,13 @@ private void ReadLogicalScreenDescriptorAndGlobalColorTable(BufferedReadStream s
int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
this.gifMetadata.GlobalColorTableLength = globalColorTableLength;

this.globalColorTable = this.MemoryAllocator.Allocate<byte>(globalColorTableLength, AllocationOptions.Clean);
if (globalColorTableLength > 0)
{
this.globalColorTable = this.MemoryAllocator.Allocate<byte>(globalColorTableLength, AllocationOptions.Clean);

// Read the global color table data from the stream
stream.Read(this.globalColorTable.GetSpan());
// Read the global color table data from the stream
stream.Read(this.globalColorTable.GetSpan());
}
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,5 +247,17 @@ TestImageProvider<Rgba32> provider
"Disco")
.Dispose();
}

// https://github.com/SixLabors/ImageSharp/issues/1962
[Theory]
[WithFile(TestImages.Gif.Issues.Issue1962NoColorTable, PixelTypes.Rgba32)]
public void Issue1962<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
image.DebugSave(provider);

image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider);
}
}
}
1 change: 1 addition & 0 deletions tests/ImageSharp.Tests/TestImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ public static class Issues
public const string Issue1505 = "Gif/issues/issue1505_argumentoutofrange.png";
public const string Issue1530 = "Gif/issues/issue1530.gif";
public const string InvalidColorIndex = "Gif/issues/issue1668_invalidcolorindex.gif";
public const string Issue1962NoColorTable = "Gif/issues/issue1962_tiniest_gif_1st.gif";
}

public static readonly string[] All = { Rings, Giphy, Cheers, Trans, Kumin, Leo, Ratio4x1, Ratio1x4 };
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions tests/Images/Input/Gif/issues/issue1962_tiniest_gif_1st.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 5d6f389

Please sign in to comment.