diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs
index 89db7ed64..c1860c9c5 100644
--- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs
+++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs
@@ -231,14 +231,14 @@ internal abstract class BitWriterBase
/// The background color is also used when the Disposal method is 1.
///
/// The number of times to loop the animation. If it is 0, this means infinitely.
- public static void WriteAnimationParameter(Stream stream, uint background, ushort loopCount)
+ public static void WriteAnimationParameter(Stream stream, Color background, ushort loopCount)
{
Span buf = stackalloc byte[4];
BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.AnimationParameter);
stream.Write(buf);
BinaryPrimitives.WriteUInt32LittleEndian(buf, sizeof(uint) + sizeof(ushort));
stream.Write(buf);
- BinaryPrimitives.WriteUInt32LittleEndian(buf, background);
+ BinaryPrimitives.WriteUInt32LittleEndian(buf, background.ToRgba32().Rgba);
stream.Write(buf);
BinaryPrimitives.WriteUInt16LittleEndian(buf[..2], loopCount);
stream.Write(buf[..2]);
@@ -249,7 +249,7 @@ internal abstract class BitWriterBase
///
/// The stream to write to.
/// Animation frame data.
- public static long WriteAnimationFrame(Stream stream, AnimationFrameData animation)
+ public static long WriteAnimationFrame(Stream stream, WebpFrameData animation)
{
Span buf = stackalloc byte[4];
BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Animation);
@@ -262,6 +262,8 @@ internal abstract class BitWriterBase
WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Width - 1);
WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Height - 1);
WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Duration);
+
+ // TODO: If we can clip the indexed frame for transparent bounds we can set properties here.
byte flag = (byte)(((int)animation.BlendingMethod << 1) | (int)animation.DisposalMethod);
stream.WriteByte(flag);
return position;
diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
index 3da27229a..9156d5bdf 100644
--- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
+++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
@@ -235,7 +235,7 @@ internal class Vp8LEncoder : IDisposable
///
public Vp8LHashChain HashChain { get; }
- public void EncodeHeader(Image image, Stream stream, bool hasAnimation, uint background = 0, uint loopCount = 0)
+ public void EncodeHeader(Image image, Stream stream, bool hasAnimation)
where TPixel : unmanaged, IPixel
{
// Write bytes from the bitwriter buffer to the stream.
@@ -257,7 +257,8 @@ internal class Vp8LEncoder : IDisposable
if (hasAnimation)
{
- BitWriterBase.WriteAnimationParameter(stream, background, (ushort)loopCount);
+ WebpMetadata webpMetadata = metadata.GetWebpMetadata();
+ BitWriterBase.WriteAnimationParameter(stream, webpMetadata.AnimationBackground, webpMetadata.AnimationLoopCount);
}
}
@@ -304,11 +305,14 @@ internal class Vp8LEncoder : IDisposable
if (hasAnimation)
{
- prevPosition = BitWriterBase.WriteAnimationFrame(stream, new AnimationFrameData
+ WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata();
+ prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData
{
Width = (uint)frame.Width,
Height = (uint)frame.Height,
- Duration = frame.Metadata.GetWebpMetadata().FrameDuration
+ Duration = frameMetadata.FrameDelay,
+ BlendingMethod = frameMetadata.BlendMethod,
+ DisposalMethod = frameMetadata.DisposalMethod
});
}
@@ -547,7 +551,7 @@ internal class Vp8LEncoder : IDisposable
EntropyIx entropyIdx = this.AnalyzeEntropy(bgra, width, height, usePalette, this.PaletteSize, this.TransformBits, out redAndBlueAlwaysZero);
bool doNotCache = false;
- List crunchConfigs = new List();
+ List crunchConfigs = new();
if (this.method == WebpEncodingMethod.BestQuality && this.quality == 100)
{
@@ -641,8 +645,8 @@ internal class Vp8LEncoder : IDisposable
Vp8LBackwardRefs refsTmp = this.Refs[refsBest.Equals(this.Refs[0]) ? 1 : 0];
this.bitWriter.Reset(bwInit);
- Vp8LHistogram tmpHisto = new Vp8LHistogram(cacheBits);
- List histogramImage = new List(histogramImageXySize);
+ Vp8LHistogram tmpHisto = new(cacheBits);
+ List histogramImage = new(histogramImageXySize);
for (int i = 0; i < histogramImageXySize; i++)
{
histogramImage.Add(new Vp8LHistogram(cacheBits));
@@ -839,7 +843,7 @@ internal class Vp8LEncoder : IDisposable
refsTmp1,
refsTmp2);
- List histogramImage = new List
+ List histogramImage = new()
{
new Vp8LHistogram(cacheBits)
};
@@ -941,7 +945,7 @@ internal class Vp8LEncoder : IDisposable
int i;
byte[] codeLengthBitDepth = new byte[WebpConstants.CodeLengthCodes];
short[] codeLengthBitDepthSymbols = new short[WebpConstants.CodeLengthCodes];
- HuffmanTreeCode huffmanCode = new HuffmanTreeCode
+ HuffmanTreeCode huffmanCode = new()
{
NumSymbols = WebpConstants.CodeLengthCodes,
CodeLengths = codeLengthBitDepth,
@@ -1192,7 +1196,7 @@ internal class Vp8LEncoder : IDisposable
histo[(int)HistoIx.HistoBluePred * 256]++;
histo[(int)HistoIx.HistoAlphaPred * 256]++;
- Vp8LBitEntropy bitEntropy = new Vp8LBitEntropy();
+ Vp8LBitEntropy bitEntropy = new();
for (int j = 0; j < (int)HistoIx.HistoTotal; j++)
{
bitEntropy.Init();
@@ -1318,7 +1322,7 @@ internal class Vp8LEncoder : IDisposable
/// The number of palette entries.
private static int GetColorPalette(ReadOnlySpan bgra, int width, int height, Span palette)
{
- HashSet colors = new HashSet();
+ HashSet colors = new();
for (int y = 0; y < height; y++)
{
ReadOnlySpan bgraRow = bgra.Slice(y * width, width);
@@ -1870,9 +1874,9 @@ internal class Vp8LEncoder : IDisposable
///
public void ClearRefs()
{
- for (int i = 0; i < this.Refs.Length; i++)
+ foreach (Vp8LBackwardRefs t in this.Refs)
{
- this.Refs[i].Refs.Clear();
+ t.Refs.Clear();
}
}
diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
index e62eb6cfc..3a6e9a2cc 100644
--- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
+++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
@@ -309,7 +309,7 @@ internal class Vp8Encoder : IDisposable
///
private int MbHeaderLimit { get; }
- public void EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation, uint background = 0, uint loopCount = 0)
+ public void EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation)
where TPixel : unmanaged, IPixel
{
// Write bytes from the bitwriter buffer to the stream.
@@ -331,7 +331,8 @@ internal class Vp8Encoder : IDisposable
if (hasAnimation)
{
- BitWriterBase.WriteAnimationParameter(stream, background, (ushort)loopCount);
+ WebpMetadata webpMetadata = metadata.GetWebpMetadata();
+ BitWriterBase.WriteAnimationParameter(stream, webpMetadata.AnimationBackground, webpMetadata.AnimationLoopCount);
}
}
@@ -395,7 +396,7 @@ internal class Vp8Encoder : IDisposable
int yStride = width;
int uvStride = (yStride + 1) >> 1;
- Vp8EncIterator it = new Vp8EncIterator(this);
+ Vp8EncIterator it = new(this);
Span alphas = stackalloc int[WebpConstants.MaxAlpha + 1];
this.alpha = this.MacroBlockAnalysis(width, height, it, y, u, v, yStride, uvStride, alphas, out this.uvAlpha);
int totalMb = this.Mbw * this.Mbw;
@@ -416,8 +417,8 @@ internal class Vp8Encoder : IDisposable
this.StatLoop(width, height, yStride, uvStride);
it.Init();
Vp8EncIterator.InitFilter();
- Vp8ModeScore info = new Vp8ModeScore();
- Vp8Residual residual = new Vp8Residual();
+ Vp8ModeScore info = new();
+ Vp8Residual residual = new();
do
{
bool dontUseSkip = !this.Proba.UseSkipProba;
@@ -474,11 +475,14 @@ internal class Vp8Encoder : IDisposable
if (hasAnimation)
{
- prevPosition = BitWriterBase.WriteAnimationFrame(stream, new AnimationFrameData
+ WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata();
+ prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData
{
Width = (uint)frame.Width,
Height = (uint)frame.Height,
- Duration = frame.Metadata.GetWebpMetadata().FrameDuration
+ Duration = frameMetadata.FrameDelay,
+ BlendingMethod = frameMetadata.BlendMethod,
+ DisposalMethod = frameMetadata.DisposalMethod
});
}
@@ -529,7 +533,7 @@ internal class Vp8Encoder : IDisposable
Vp8RdLevel rdOpt = this.method >= WebpEncodingMethod.Level3 || doSearch ? Vp8RdLevel.RdOptBasic : Vp8RdLevel.RdOptNone;
int nbMbs = this.Mbw * this.Mbh;
- PassStats stats = new PassStats(targetSize, targetPsnr, QMin, QMax, this.quality);
+ PassStats stats = new(targetSize, targetPsnr, QMin, QMax, this.quality);
this.Proba.ResetTokenStats();
// Fast mode: quick analysis pass over few mbs. Better than nothing.
@@ -597,7 +601,7 @@ internal class Vp8Encoder : IDisposable
Span y = this.Y.GetSpan();
Span u = this.U.GetSpan();
Span v = this.V.GetSpan();
- Vp8EncIterator it = new Vp8EncIterator(this);
+ Vp8EncIterator it = new(this);
long size = 0;
long sizeP0 = 0;
long distortion = 0;
@@ -605,7 +609,7 @@ internal class Vp8Encoder : IDisposable
it.Init();
this.SetLoopParams(stats.Q);
- Vp8ModeScore info = new Vp8ModeScore();
+ Vp8ModeScore info = new();
do
{
info.Clear();
@@ -1167,7 +1171,7 @@ internal class Vp8Encoder : IDisposable
private void RecordResiduals(Vp8EncIterator it, Vp8ModeScore rd)
{
int x, y, ch;
- Vp8Residual residual = new Vp8Residual();
+ Vp8Residual residual = new();
bool i16 = it.CurrentMacroBlockInfo.MacroBlockType == Vp8MacroBlockType.I16X16;
it.NzToBytes();
diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
index 6922e37d6..87657dfab 100644
--- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
+++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
@@ -138,7 +138,7 @@ internal class WebpAnimationDecoder : IDisposable
private uint ReadFrame(BufferedReadStream stream, ref Image? image, ref ImageFrame? previousFrame, uint width, uint height, Color backgroundColor)
where TPixel : unmanaged, IPixel
{
- AnimationFrameData frameData = AnimationFrameData.Parse(stream);
+ WebpFrameData frameData = WebpFrameData.Parse(stream);
long streamStartPosition = stream.Position;
Span buffer = stackalloc byte[4];
@@ -153,7 +153,7 @@ internal class WebpAnimationDecoder : IDisposable
}
WebpImageInfo? webpInfo = null;
- WebpFeatures features = new WebpFeatures();
+ WebpFeatures features = new();
switch (chunkType)
{
case WebpChunkType.Vp8:
@@ -180,7 +180,7 @@ internal class WebpAnimationDecoder : IDisposable
{
image = new Image(this.configuration, (int)width, (int)height, backgroundColor.ToPixel(), this.metadata);
- SetFrameMetadata(image.Frames.RootFrame.Metadata, frameData.Duration);
+ SetFrameMetadata(image.Frames.RootFrame.Metadata, frameData);
imageFrame = image.Frames.RootFrame;
}
@@ -188,7 +188,7 @@ internal class WebpAnimationDecoder : IDisposable
{
currentFrame = image!.Frames.AddFrame(previousFrame); // This clones the frame and adds it the collection.
- SetFrameMetadata(currentFrame.Metadata, frameData.Duration);
+ SetFrameMetadata(currentFrame.Metadata, frameData);
imageFrame = currentFrame;
}
@@ -199,7 +199,7 @@ internal class WebpAnimationDecoder : IDisposable
int frameHeight = (int)frameData.Height;
Rectangle regionRectangle = Rectangle.FromLTRB(frameX, frameY, frameX + frameWidth, frameY + frameHeight);
- if (frameData.DisposalMethod is AnimationDisposalMethod.Dispose)
+ if (frameData.DisposalMethod is WebpDisposalMethod.Dispose)
{
this.RestoreToBackground(imageFrame, backgroundColor);
}
@@ -207,7 +207,7 @@ internal class WebpAnimationDecoder : IDisposable
using Buffer2D decodedImage = this.DecodeImageData(frameData, webpInfo);
DrawDecodedImageOnCanvas(decodedImage, imageFrame, frameX, frameY, frameWidth, frameHeight);
- if (previousFrame != null && frameData.BlendingMethod is AnimationBlendingMethod.AlphaBlending)
+ if (previousFrame != null && frameData.BlendingMethod is WebpBlendingMethod.AlphaBlending)
{
this.AlphaBlend(previousFrame, imageFrame, frameX, frameY, frameWidth, frameHeight);
}
@@ -222,12 +222,13 @@ internal class WebpAnimationDecoder : IDisposable
/// Sets the frames metadata.
///
/// The metadata.
- /// The frame duration.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void SetFrameMetadata(ImageFrameMetadata meta, uint duration)
+ /// The frame data.
+ private static void SetFrameMetadata(ImageFrameMetadata meta, WebpFrameData frameData)
{
WebpFrameMetadata frameMetadata = meta.GetWebpMetadata();
- frameMetadata.FrameDuration = duration;
+ frameMetadata.FrameDelay = frameData.Duration;
+ frameMetadata.BlendMethod = frameData.BlendingMethod;
+ frameMetadata.DisposalMethod = frameData.DisposalMethod;
}
///
@@ -256,10 +257,10 @@ internal class WebpAnimationDecoder : IDisposable
/// The frame data.
/// The webp information.
/// A decoded image.
- private Buffer2D DecodeImageData(AnimationFrameData frameData, WebpImageInfo webpInfo)
+ private Buffer2D DecodeImageData(WebpFrameData frameData, WebpImageInfo webpInfo)
where TPixel : unmanaged, IPixel
{
- Image decodedImage = new Image((int)frameData.Width, (int)frameData.Height);
+ Image decodedImage = new((int)frameData.Width, (int)frameData.Height);
try
{
@@ -267,13 +268,13 @@ internal class WebpAnimationDecoder : IDisposable
if (webpInfo.IsLossless)
{
WebpLosslessDecoder losslessDecoder =
- new WebpLosslessDecoder(webpInfo.Vp8LBitReader, this.memoryAllocator, this.configuration);
+ new(webpInfo.Vp8LBitReader, this.memoryAllocator, this.configuration);
losslessDecoder.Decode(pixelBufferDecoded, (int)webpInfo.Width, (int)webpInfo.Height);
}
else
{
WebpLossyDecoder lossyDecoder =
- new WebpLossyDecoder(webpInfo.Vp8BitReader, this.memoryAllocator, this.configuration);
+ new(webpInfo.Vp8BitReader, this.memoryAllocator, this.configuration);
lossyDecoder.Decode(pixelBufferDecoded, (int)webpInfo.Width, (int)webpInfo.Height, webpInfo, this.alphaData);
}
diff --git a/src/ImageSharp/Formats/Webp/AnimationBlendingMethod.cs b/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs
similarity index 95%
rename from src/ImageSharp/Formats/Webp/AnimationBlendingMethod.cs
rename to src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs
index 99b2462ce..cbd0e9a8c 100644
--- a/src/ImageSharp/Formats/Webp/AnimationBlendingMethod.cs
+++ b/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs
@@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp;
///
/// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas.
///
-internal enum AnimationBlendingMethod
+public enum WebpBlendingMethod
{
///
/// Use alpha blending. After disposing of the previous frame, render the current frame on the canvas using alpha-blending.
diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
index bc875c889..de188b137 100644
--- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
@@ -73,7 +73,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
public DecoderOptions Options { get; }
///
- public Size Dimensions => new Size((int)this.webImageInfo!.Width, (int)this.webImageInfo.Height);
+ public Size Dimensions => new((int)this.webImageInfo!.Width, (int)this.webImageInfo.Height);
///
public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken)
@@ -82,7 +82,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
Image? image = null;
try
{
- ImageMetadata metadata = new ImageMetadata();
+ ImageMetadata metadata = new();
Span buffer = stackalloc byte[4];
uint fileSize = ReadImageHeader(stream, buffer);
@@ -91,7 +91,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
{
if (this.webImageInfo.Features is { Animation: true })
{
- using WebpAnimationDecoder animationDecoder = new WebpAnimationDecoder(
+ using WebpAnimationDecoder animationDecoder = new(
this.memoryAllocator,
this.configuration,
this.maxFrames,
@@ -103,7 +103,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
Buffer2D pixels = image.GetRootFramePixelBuffer();
if (this.webImageInfo.IsLossless)
{
- WebpLosslessDecoder losslessDecoder = new WebpLosslessDecoder(
+ WebpLosslessDecoder losslessDecoder = new(
this.webImageInfo.Vp8LBitReader,
this.memoryAllocator,
this.configuration);
@@ -111,7 +111,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
}
else
{
- WebpLossyDecoder lossyDecoder = new WebpLossyDecoder(
+ WebpLossyDecoder lossyDecoder = new(
this.webImageInfo.Vp8BitReader,
this.memoryAllocator,
this.configuration);
@@ -139,7 +139,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
{
ReadImageHeader(stream, stackalloc byte[4]);
- ImageMetadata metadata = new ImageMetadata();
+ ImageMetadata metadata = new();
using (this.webImageInfo = this.ReadVp8Info(stream, metadata, true))
{
return new ImageInfo(
@@ -185,7 +185,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
Span buffer = stackalloc byte[4];
WebpChunkType chunkType = WebpChunkParsingUtils.ReadChunkType(stream, buffer);
- WebpFeatures features = new WebpFeatures();
+ WebpFeatures features = new();
switch (chunkType)
{
case WebpChunkType.Vp8:
@@ -392,7 +392,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the iccp chunk");
}
- IccProfile profile = new IccProfile(iccpData);
+ IccProfile profile = new(iccpData);
if (profile.CheckIsValid())
{
metadata.IccProfile = profile;
diff --git a/src/ImageSharp/Formats/Webp/AnimationDisposalMethod.cs b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs
similarity index 94%
rename from src/ImageSharp/Formats/Webp/AnimationDisposalMethod.cs
rename to src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs
index 23bc37c28..d409973a9 100644
--- a/src/ImageSharp/Formats/Webp/AnimationDisposalMethod.cs
+++ b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs
@@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp;
///
/// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas.
///
-internal enum AnimationDisposalMethod
+public enum WebpDisposalMethod
{
///
/// Do not dispose. Leave the canvas as is.
diff --git a/src/ImageSharp/Formats/Webp/WebpEncoder.cs b/src/ImageSharp/Formats/Webp/WebpEncoder.cs
index 13c9798db..bc93df3a5 100644
--- a/src/ImageSharp/Formats/Webp/WebpEncoder.cs
+++ b/src/ImageSharp/Formats/Webp/WebpEncoder.cs
@@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-using SixLabors.ImageSharp.Advanced;
-
namespace SixLabors.ImageSharp.Formats.Webp;
///
@@ -82,7 +80,7 @@ public sealed class WebpEncoder : ImageEncoder
///
protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken)
{
- WebpEncoderCore encoder = new WebpEncoderCore(this, image.Configuration);
+ WebpEncoderCore encoder = new(this, image.Configuration);
encoder.Encode(image, stream, cancellationToken);
}
}
diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
index d945cc399..47712071b 100644
--- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
@@ -129,7 +129,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
if (lossless)
{
- using Vp8LEncoder encoder = new Vp8LEncoder(
+ using Vp8LEncoder encoder = new(
this.memoryAllocator,
this.configuration,
image.Width,
@@ -147,7 +147,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
{
foreach (ImageFrame imageFrame in image.Frames)
{
- using Vp8LEncoder enc = new Vp8LEncoder(
+ using Vp8LEncoder enc = new(
this.memoryAllocator,
this.configuration,
image.Width,
@@ -171,7 +171,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
}
else
{
- using Vp8Encoder encoder = new Vp8Encoder(
+ using Vp8Encoder encoder = new(
this.memoryAllocator,
this.configuration,
image.Width,
@@ -189,7 +189,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
foreach (ImageFrame imageFrame in image.Frames)
{
- using Vp8Encoder enc = new Vp8Encoder(
+ using Vp8Encoder enc = new(
this.memoryAllocator,
this.configuration,
image.Width,
diff --git a/src/ImageSharp/Formats/Webp/AnimationFrameData.cs b/src/ImageSharp/Formats/Webp/WebpFrameData.cs
similarity index 83%
rename from src/ImageSharp/Formats/Webp/AnimationFrameData.cs
rename to src/ImageSharp/Formats/Webp/WebpFrameData.cs
index 27a1815fe..e2bcfd7c3 100644
--- a/src/ImageSharp/Formats/Webp/AnimationFrameData.cs
+++ b/src/ImageSharp/Formats/Webp/WebpFrameData.cs
@@ -5,7 +5,7 @@ using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Formats.Webp;
-internal struct AnimationFrameData
+internal struct WebpFrameData
{
///
/// The animation chunk size.
@@ -46,23 +46,23 @@ internal struct AnimationFrameData
///
/// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas.
///
- public AnimationBlendingMethod BlendingMethod;
+ public WebpBlendingMethod BlendingMethod;
///
/// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas.
///
- public AnimationDisposalMethod DisposalMethod;
+ public WebpDisposalMethod DisposalMethod;
///
/// Reads the animation frame header.
///
/// The stream to read from.
/// Animation frame data.
- public static AnimationFrameData Parse(BufferedReadStream stream)
+ public static WebpFrameData Parse(BufferedReadStream stream)
{
Span buffer = stackalloc byte[4];
- AnimationFrameData data = new AnimationFrameData
+ WebpFrameData data = new()
{
DataSize = WebpChunkParsingUtils.ReadChunkSize(stream, buffer),
@@ -83,8 +83,8 @@ internal struct AnimationFrameData
};
byte flags = (byte)stream.ReadByte();
- data.DisposalMethod = (flags & 1) == 1 ? AnimationDisposalMethod.Dispose : AnimationDisposalMethod.DoNotDispose;
- data.BlendingMethod = (flags & (1 << 1)) != 0 ? AnimationBlendingMethod.DoNotBlend : AnimationBlendingMethod.AlphaBlending;
+ data.DisposalMethod = (flags & 1) == 1 ? WebpDisposalMethod.Dispose : WebpDisposalMethod.DoNotDispose;
+ data.BlendingMethod = (flags & (1 << 1)) != 0 ? WebpBlendingMethod.DoNotBlend : WebpBlendingMethod.AlphaBlending;
return data;
}
diff --git a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs
index bce1b09d6..ef21d8b6f 100644
--- a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs
+++ b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs
@@ -19,13 +19,28 @@ public class WebpFrameMetadata : IDeepCloneable
/// Initializes a new instance of the class.
///
/// The metadata to create an instance from.
- private WebpFrameMetadata(WebpFrameMetadata other) => this.FrameDuration = other.FrameDuration;
+ private WebpFrameMetadata(WebpFrameMetadata other)
+ {
+ this.FrameDelay = other.FrameDelay;
+ this.DisposalMethod = other.DisposalMethod;
+ this.BlendMethod = other.BlendMethod;
+ }
+
+ ///
+ /// Gets or sets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas.
+ ///
+ public WebpBlendingMethod BlendMethod { get; set; }
+
+ ///
+ /// Gets or sets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas.
+ ///
+ public WebpDisposalMethod DisposalMethod { get; set; }
///
/// Gets or sets the frame duration. The time to wait before displaying the next frame,
/// in 1 millisecond units. Note the interpretation of frame duration of 0 (and often smaller and equal to 10) is implementation defined.
///
- public uint FrameDuration { get; set; }
+ public uint FrameDelay { get; set; }
///
public IDeepCloneable DeepClone() => new WebpFrameMetadata(this);
diff --git a/src/ImageSharp/Formats/Webp/WebpMetadata.cs b/src/ImageSharp/Formats/Webp/WebpMetadata.cs
index 5d1051c75..a6bb0a7b8 100644
--- a/src/ImageSharp/Formats/Webp/WebpMetadata.cs
+++ b/src/ImageSharp/Formats/Webp/WebpMetadata.cs
@@ -23,6 +23,7 @@ public class WebpMetadata : IDeepCloneable
{
this.FileFormat = other.FileFormat;
this.AnimationLoopCount = other.AnimationLoopCount;
+ this.AnimationBackground = other.AnimationBackground;
}
///
@@ -35,6 +36,14 @@ public class WebpMetadata : IDeepCloneable
///
public ushort AnimationLoopCount { get; set; } = 1;
+ ///
+ /// Gets or sets the default background color of the canvas in [Blue, Green, Red, Alpha] byte order.
+ /// This color MAY be used to fill the unused space on the canvas around the frames,
+ /// as well as the transparent pixels of the first frame.
+ /// The background color is also used when the Disposal method is 1.
+ ///
+ public Color AnimationBackground { get; set; }
+
///
public IDeepCloneable DeepClone() => new WebpMetadata(this);
}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
index c0fc00b82..c3a777c15 100644
--- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
@@ -308,7 +308,7 @@ public class WebpDecoderTests
image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact);
Assert.Equal(0, webpMetaData.AnimationLoopCount);
- Assert.Equal(150U, frameMetaData.FrameDuration);
+ Assert.Equal(150U, frameMetaData.FrameDelay);
Assert.Equal(12, image.Frames.Count);
}
@@ -325,7 +325,7 @@ public class WebpDecoderTests
image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Tolerant(0.04f));
Assert.Equal(0, webpMetaData.AnimationLoopCount);
- Assert.Equal(150U, frameMetaData.FrameDuration);
+ Assert.Equal(150U, frameMetaData.FrameDelay);
Assert.Equal(12, image.Frames.Count);
}