diff --git a/src/ImageSharp/Formats/Webp/IWebpDecoderOptions.cs b/src/ImageSharp/Formats/Webp/IWebpDecoderOptions.cs
index 7bd78da3d..cf607ef69 100644
--- a/src/ImageSharp/Formats/Webp/IWebpDecoderOptions.cs
+++ b/src/ImageSharp/Formats/Webp/IWebpDecoderOptions.cs
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
+using SixLabors.ImageSharp.Metadata;
+
namespace SixLabors.ImageSharp.Formats.Webp
{
///
@@ -12,5 +14,10 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
///
bool IgnoreMetadata { get; }
+
+ ///
+ /// Gets the decoding mode for multi-frame images.
+ ///
+ FrameDecodingMode DecodingMode { get; }
}
}
diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
index 60d41c984..16589e50f 100644
--- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
+++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
@@ -53,10 +53,12 @@ namespace SixLabors.ImageSharp.Formats.Webp
///
/// The memory allocator.
/// The global configuration.
- public WebpAnimationDecoder(MemoryAllocator memoryAllocator, Configuration configuration)
+ /// The frame decoding mode.
+ public WebpAnimationDecoder(MemoryAllocator memoryAllocator, Configuration configuration, FrameDecodingMode decodingMode)
{
this.memoryAllocator = memoryAllocator;
this.configuration = configuration;
+ this.DecodingMode = decodingMode;
}
///
@@ -64,6 +66,11 @@ namespace SixLabors.ImageSharp.Formats.Webp
///
public IMemoryOwner AlphaData { get; set; }
+ ///
+ /// Gets the decoding mode for multi-frame images.
+ ///
+ public FrameDecodingMode DecodingMode { get; }
+
///
/// Decodes the animated webp image from the specified stream.
///
@@ -103,7 +110,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
break;
}
- if (stream.Position == stream.Length)
+ if (stream.Position == stream.Length || this.DecodingMode is FrameDecodingMode.First)
{
break;
}
diff --git a/src/ImageSharp/Formats/Webp/WebpDecoder.cs b/src/ImageSharp/Formats/Webp/WebpDecoder.cs
index 1736e97ce..71b4e4f23 100644
--- a/src/ImageSharp/Formats/Webp/WebpDecoder.cs
+++ b/src/ImageSharp/Formats/Webp/WebpDecoder.cs
@@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Webp
@@ -20,6 +21,12 @@ namespace SixLabors.ImageSharp.Formats.Webp
///
public bool IgnoreMetadata { get; set; }
+ ///
+ /// Gets or sets the decoding mode for multi-frame images.
+ /// Defaults to All.
+ ///
+ public FrameDecodingMode DecodingMode { get; set; } = FrameDecodingMode.All;
+
///
public Image Decode(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel
diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
index 01e604a4b..252af7867 100644
--- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
@@ -56,10 +56,19 @@ namespace SixLabors.ImageSharp.Formats.Webp
public WebpDecoderCore(Configuration configuration, IWebpDecoderOptions options)
{
this.Configuration = configuration;
+ this.DecodingMode = options.DecodingMode;
this.memoryAllocator = configuration.MemoryAllocator;
this.IgnoreMetadata = options.IgnoreMetadata;
}
+ ///
+ public Configuration Configuration { get; }
+
+ ///
+ /// Gets the decoding mode for multi-frame images.
+ ///
+ public FrameDecodingMode DecodingMode { get; }
+
///
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
///
@@ -70,9 +79,6 @@ namespace SixLabors.ImageSharp.Formats.Webp
///
public ImageMetadata Metadata { get; private set; }
- ///
- public Configuration Configuration { get; }
-
///
/// Gets the dimensions of the image.
///
@@ -96,7 +102,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
{
if (this.webImageInfo.Features is { Animation: true })
{
- using var animationDecoder = new WebpAnimationDecoder(this.memoryAllocator, this.Configuration);
+ using var animationDecoder = new WebpAnimationDecoder(this.memoryAllocator, this.Configuration, this.DecodingMode);
return animationDecoder.Decode(stream, this.webImageInfo.Features, this.webImageInfo.Width, this.webImageInfo.Height, fileSize);
}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
index ae1dddba0..5e878f780 100644
--- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
@@ -3,6 +3,7 @@
using System.IO;
using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
@@ -234,7 +235,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp
// TODO: Reference decoder throws here MagickCorruptImageErrorException, webpinfo also indicates an error here, but decoding the image seems to work.
// [WithFile(Lossless.GreenTransform5, PixelTypes.Rgba32)]
- public void WebpDecoder_CanDecode_Lossless_WithSubstractGreenTransform(
+ public void WebpDecoder_CanDecode_Lossless_WithSubtractGreenTransform(
TestImageProvider provider)
where TPixel : unmanaged, IPixel
{
@@ -345,6 +346,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp
Assert.Equal(0, webpMetaData.AnimationLoopCount);
Assert.Equal(150U, frameMetaData.FrameDuration);
+ Assert.Equal(12, image.Frames.Count);
}
}
@@ -363,6 +365,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp
Assert.Equal(0, webpMetaData.AnimationLoopCount);
Assert.Equal(150U, frameMetaData.FrameDuration);
+ Assert.Equal(12, image.Frames.Count);
+ }
+ }
+
+ [Theory]
+ [WithFile(Lossless.Animated, PixelTypes.Rgba32)]
+ public void Decode_AnimatedLossless_WithFrameDecodingModeFirst_OnlyDecodesOneFrame(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using (Image image = provider.GetImage(new WebpDecoder() { DecodingMode = FrameDecodingMode.First }))
+ {
+ Assert.Equal(1, image.Frames.Count);
}
}