diff --git a/src/ImageSharp/Formats/Gif/FrameDecodingMode.cs b/src/ImageSharp/Formats/Gif/FrameDecodingMode.cs
new file mode 100644
index 000000000..05791c92e
--- /dev/null
+++ b/src/ImageSharp/Formats/Gif/FrameDecodingMode.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Gif
+{
+ ///
+ /// Enumerated frame process modes to apply to multi-frame images.
+ ///
+ public enum FrameDecodingMode
+ {
+ ///
+ /// Decodes all the frames of a multi-frame image.
+ ///
+ All,
+
+ ///
+ /// Decodes only the first frame of a multi-frame image.
+ ///
+ First
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs
index 5ded251e2..11b5b57fa 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs
@@ -24,6 +24,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding;
+ ///
+ /// Gets or sets the decoding mode for multi-frame images
+ ///
+ public FrameDecodingMode DecodingMode { get; set; } = FrameDecodingMode.All;
+
///
public Image Decode(Configuration configuration, Stream stream)
where TPixel : struct, IPixel
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 7fa3aa04a..453197b0c 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -84,6 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
this.TextEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding;
this.IgnoreMetadata = options.IgnoreMetadata;
+ this.DecodingMode = options.DecodingMode;
this.configuration = configuration ?? Configuration.Default;
}
@@ -97,6 +98,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
public Encoding TextEncoding { get; }
+ ///
+ /// Gets the decoding mode for multi-frame images
+ ///
+ public FrameDecodingMode DecodingMode { get; }
+
///
/// Decodes the stream to the image.
///
@@ -129,6 +135,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
if (nextFlag == GifConstants.ImageLabel)
{
+ if (this.previousFrame != null && this.DecodingMode == FrameDecodingMode.First)
+ {
+ break;
+ }
+
this.ReadFrame();
}
else if (nextFlag == GifConstants.ExtensionIntroducer)
@@ -238,14 +249,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
throw new ImageFormatException($"Invalid gif colormap size '{this.logicalScreenDescriptor.GlobalColorTableSize}'");
}
-
- /* // No point doing this as the max width/height is always int.Max and that always bigger than the max size of a gif which is stored in a short.
- if (this.logicalScreenDescriptor.Width > Image.MaxWidth || this.logicalScreenDescriptor.Height > Image.MaxHeight)
- {
- throw new ArgumentOutOfRangeException(
- $"The input gif '{this.logicalScreenDescriptor.Width}x{this.logicalScreenDescriptor.Height}' is bigger then the max allowed size '{Image.MaxWidth}x{Image.MaxHeight}'");
- }
- */
}
///
diff --git a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs
index fd4cc82c9..a2288f30a 100644
--- a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs
+++ b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs
@@ -19,5 +19,10 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// Gets the encoding that should be used when reading comments.
///
Encoding TextEncoding { get; }
+
+ ///
+ /// Gets the decoding mode for multi-frame images
+ ///
+ FrameDecodingMode DecodingMode { get; }
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
index d04c49a98..cd78add75 100644
--- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Text;
-using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -45,12 +44,12 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Decode_IgnoreMetadataIsFalse_CommentsAreRead()
{
- GifDecoder options = new GifDecoder()
+ var options = new GifDecoder
{
IgnoreMetadata = false
};
- TestFile testFile = TestFile.Create(TestImages.Gif.Rings);
+ var testFile = TestFile.Create(TestImages.Gif.Rings);
using (Image image = testFile.CreateImage(options))
{
@@ -63,12 +62,12 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Decode_IgnoreMetadataIsTrue_CommentsAreIgnored()
{
- GifDecoder options = new GifDecoder()
+ var options = new GifDecoder
{
IgnoreMetadata = true
};
- TestFile testFile = TestFile.Create(TestImages.Gif.Rings);
+ var testFile = TestFile.Create(TestImages.Gif.Rings);
using (Image image = testFile.CreateImage(options))
{
@@ -79,12 +78,12 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding()
{
- GifDecoder options = new GifDecoder()
+ var options = new GifDecoder
{
TextEncoding = Encoding.Unicode
};
- TestFile testFile = TestFile.Create(TestImages.Gif.Rings);
+ var testFile = TestFile.Create(TestImages.Gif.Rings);
using (Image image = testFile.CreateImage(options))
{
@@ -92,5 +91,27 @@ namespace SixLabors.ImageSharp.Tests
Assert.Equal("浉条卥慨灲", image.MetaData.Properties[0].Value);
}
}
+
+ [Theory]
+ [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)]
+ public void CanDecodeJustOneFrame(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ using (Image image = provider.GetImage(new GifDecoder { DecodingMode = FrameDecodingMode.First }))
+ {
+ Assert.Equal(1, image.Frames.Count);
+ }
+ }
+
+ [Theory]
+ [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)]
+ public void CanDecodeAllFrames(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ using (Image image = provider.GetImage(new GifDecoder { DecodingMode = FrameDecodingMode.All }))
+ {
+ Assert.True(image.Frames.Count > 1);
+ }
+ }
}
-}
+}
\ No newline at end of file