Skip to content

Commit f0c3ec6

Browse files
Merge branch 'main' into progressive-jpeg-encoder
2 parents dc5affa + 339b26d commit f0c3ec6

File tree

14 files changed

+77
-16
lines changed

14 files changed

+77
-16
lines changed

src/ImageSharp/Formats/Gif/LzwDecoder.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ internal sealed class LzwDecoder : IDisposable
1919
/// </summary>
2020
private const int MaxStackSize = 4096;
2121

22+
/// <summary>
23+
/// The maximum bits for a lzw code.
24+
/// </summary>
25+
private const int MaximumLzwBits = 12;
26+
2227
/// <summary>
2328
/// The null code.
2429
/// </summary>
@@ -73,12 +78,12 @@ public void DecodePixels(int minCodeSize, Buffer2D<byte> pixels)
7378
// It is possible to specify a larger LZW minimum code size than the palette length in bits
7479
// which may leave a gap in the codes where no colors are assigned.
7580
// http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression
76-
if (minCodeSize < 2 || clearCode > MaxStackSize)
81+
if (minCodeSize < 2 || minCodeSize > MaximumLzwBits || clearCode > MaxStackSize)
7782
{
7883
// Don't attempt to decode the frame indices.
7984
// Theoretically we could determine a min code size from the length of the provided
8085
// color palette but we won't bother since the image is most likely corrupted.
81-
GifThrowHelper.ThrowInvalidImageContentException("Gif Image does not contain a valid LZW minimum code.");
86+
return;
8287
}
8388

8489
// The resulting index table length.
@@ -245,12 +250,12 @@ public void SkipIndices(int minCodeSize, int length)
245250
// It is possible to specify a larger LZW minimum code size than the palette length in bits
246251
// which may leave a gap in the codes where no colors are assigned.
247252
// http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression
248-
if (minCodeSize < 2 || clearCode > MaxStackSize)
253+
if (minCodeSize < 2 || minCodeSize > MaximumLzwBits || clearCode > MaxStackSize)
249254
{
250255
// Don't attempt to decode the frame indices.
251256
// Theoretically we could determine a min code size from the length of the provided
252257
// color palette but we won't bother since the image is most likely corrupted.
253-
GifThrowHelper.ThrowInvalidImageContentException("Gif Image does not contain a valid LZW minimum code.");
258+
return;
254259
}
255260

256261
int codeSize = minCodeSize + 1;

tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,9 @@ public void Issue2012EmptyXmp<TPixel>(TestImageProvider<TPixel> provider)
296296
public void Issue2012BadMinCode<TPixel>(TestImageProvider<TPixel> provider)
297297
where TPixel : unmanaged, IPixel<TPixel>
298298
{
299-
Exception ex = Record.Exception(
300-
() =>
301-
{
302-
using Image<TPixel> image = provider.GetImage();
303-
image.DebugSave(provider);
304-
});
305-
306-
Assert.NotNull(ex);
307-
Assert.Contains("Gif Image does not contain a valid LZW minimum code.", ex.Message);
299+
using Image<TPixel> image = provider.GetImage();
300+
image.DebugSave(provider);
301+
image.CompareToReferenceOutput(provider);
308302
}
309303

310304
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
@@ -318,4 +312,15 @@ public void IssueDeferredClearCode<TPixel>(TestImageProvider<TPixel> provider)
318312
image.DebugSave(provider);
319313
image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider);
320314
}
315+
316+
// https://github.com/SixLabors/ImageSharp/issues/2743
317+
[Theory]
318+
[WithFile(TestImages.Gif.Issues.BadMaxLzwBits, PixelTypes.Rgba32)]
319+
public void IssueTooLargeLzwBits<TPixel>(TestImageProvider<TPixel> provider)
320+
where TPixel : unmanaged, IPixel<TPixel>
321+
{
322+
using Image<TPixel> image = provider.GetImage();
323+
image.DebugSaveMultiFrame(provider);
324+
image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact);
325+
}
321326
}

tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public void CloneIsDeep()
3535
RepeatCount = 1,
3636
ColorTableMode = GifColorTableMode.Global,
3737
GlobalColorTable = new[] { Color.Black, Color.White },
38-
Comments = new List<string> { "Foo" }
38+
Comments = ["Foo"]
3939
};
4040

4141
GifMetadata clone = (GifMetadata)meta.DeepClone();
@@ -126,7 +126,7 @@ public void Identify_VerifyRatio(string imagePath, int xResolution, int yResolut
126126
public async Task Identify_VerifyRatioAsync(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
127127
{
128128
TestFile testFile = TestFile.Create(imagePath);
129-
using MemoryStream stream = new(testFile.Bytes, false);
129+
await using MemoryStream stream = new(testFile.Bytes, false);
130130
ImageInfo image = await GifDecoder.Instance.IdentifyAsync(DecoderOptions.Default, stream);
131131
ImageMetadata meta = image.Metadata;
132132
Assert.Equal(xResolution, meta.HorizontalResolution);
@@ -152,7 +152,7 @@ public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolutio
152152
public async Task Decode_VerifyRatioAsync(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
153153
{
154154
TestFile testFile = TestFile.Create(imagePath);
155-
using MemoryStream stream = new(testFile.Bytes, false);
155+
await using MemoryStream stream = new(testFile.Bytes, false);
156156
using Image<Rgba32> image = await GifDecoder.Instance.DecodeAsync<Rgba32>(DecoderOptions.Default, stream);
157157
ImageMetadata meta = image.Metadata;
158158
Assert.Equal(xResolution, meta.HorizontalResolution);
@@ -214,4 +214,24 @@ public void Identify_Frames(
214214
Assert.Equal(frameDelay, gifFrameMetadata.FrameDelay);
215215
Assert.Equal(disposalMethod, gifFrameMetadata.DisposalMethod);
216216
}
217+
218+
[Theory]
219+
[InlineData(TestImages.Gif.Issues.BadMaxLzwBits, 8)]
220+
[InlineData(TestImages.Gif.Issues.Issue2012BadMinCode, 1)]
221+
public void Identify_Frames_Bad_Lzw(string imagePath, int framesCount)
222+
{
223+
TestFile testFile = TestFile.Create(imagePath);
224+
using MemoryStream stream = new(testFile.Bytes, false);
225+
226+
ImageInfo imageInfo = Image.Identify(stream);
227+
228+
Assert.NotNull(imageInfo);
229+
GifMetadata gifMetadata = imageInfo.Metadata.GetGifMetadata();
230+
Assert.NotNull(gifMetadata);
231+
232+
Assert.Equal(framesCount, imageInfo.FrameMetadataCollection.Count);
233+
GifFrameMetadata gifFrameMetadata = imageInfo.FrameMetadataCollection[imageInfo.FrameMetadataCollection.Count - 1].GetGifMetadata();
234+
235+
Assert.NotNull(gifFrameMetadata);
236+
}
217237
}

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ public static class Issues
516516
public const string BadAppExtLength = "Gif/issues/issue405_badappextlength252.gif";
517517
public const string BadAppExtLength_2 = "Gif/issues/issue405_badappextlength252-2.gif";
518518
public const string BadDescriptorWidth = "Gif/issues/issue403_baddescriptorwidth.gif";
519+
public const string BadMaxLzwBits = "Gif/issues/issue_2743.gif";
519520
public const string DeferredClearCode = "Gif/issues/bugzilla-55918.gif";
520521
public const string Issue1505 = "Gif/issues/issue1505_argumentoutofrange.png";
521522
public const string Issue1530 = "Gif/issues/issue1530.gif";
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)