Skip to content

Commit

Permalink
Add new member to WebpFrameMetadata
Browse files Browse the repository at this point in the history
  • Loading branch information
Poker-sang committed Oct 31, 2023
1 parent 5737e4a commit 8d2f255
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 49 deletions.
4 changes: 3 additions & 1 deletion src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public static void WriteAnimationParameter(Stream stream, uint background, ushor
/// </summary>
/// <param name="stream">The stream to write to.</param>
/// <param name="animation">Animation frame data.</param>
public static long WriteAnimationFrame(Stream stream, AnimationFrameData animation)
public static long WriteAnimationFrame(Stream stream, WebpFrameData animation)
{
Span<byte> buf = stackalloc byte[4];
BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Animation);
Expand All @@ -262,6 +262,8 @@ public static long WriteAnimationFrame(Stream stream, AnimationFrameData animati
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;
Expand Down
4 changes: 2 additions & 2 deletions src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,11 +304,11 @@ public void Encode<TPixel>(ImageFrame<TPixel> frame, Stream stream, bool hasAnim

if (hasAnimation)
{
prevPosition = BitWriterBase.WriteAnimationFrame(stream, new AnimationFrameData
prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData
{
Width = (uint)frame.Width,
Height = (uint)frame.Height,
Duration = frame.Metadata.GetWebpMetadata().FrameDuration
Duration = frame.Metadata.GetWebpMetadata().FrameDelay
});
}

Expand Down
18 changes: 9 additions & 9 deletions src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ private void Encode<TPixel>(ImageFrame<TPixel> frame, Stream stream, bool hasAni
int yStride = width;
int uvStride = (yStride + 1) >> 1;

Vp8EncIterator it = new Vp8EncIterator(this);
Vp8EncIterator it = new(this);
Span<int> 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;
Expand All @@ -416,8 +416,8 @@ private void Encode<TPixel>(ImageFrame<TPixel> frame, Stream stream, bool hasAni
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;
Expand Down Expand Up @@ -474,11 +474,11 @@ private void Encode<TPixel>(ImageFrame<TPixel> frame, Stream stream, bool hasAni

if (hasAnimation)
{
prevPosition = BitWriterBase.WriteAnimationFrame(stream, new AnimationFrameData
prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData
{
Width = (uint)frame.Width,
Height = (uint)frame.Height,
Duration = frame.Metadata.GetWebpMetadata().FrameDuration
Duration = frame.Metadata.GetWebpMetadata().FrameDelay
});
}

Expand Down Expand Up @@ -529,7 +529,7 @@ private void StatLoop(int width, int height, int yStride, int uvStride)
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.
Expand Down Expand Up @@ -597,15 +597,15 @@ private long OneStatPass(int width, int height, int yStride, int uvStride, Vp8Rd
Span<byte> y = this.Y.GetSpan();
Span<byte> u = this.U.GetSpan();
Span<byte> v = this.V.GetSpan();
Vp8EncIterator it = new Vp8EncIterator(this);
Vp8EncIterator it = new(this);
long size = 0;
long sizeP0 = 0;
long distortion = 0;
long pixelCount = nbMbs * 384;

it.Init();
this.SetLoopParams(stats.Q);
Vp8ModeScore info = new Vp8ModeScore();
Vp8ModeScore info = new();
do
{
info.Clear();
Expand Down Expand Up @@ -1167,7 +1167,7 @@ private void CodeResiduals(Vp8EncIterator it, Vp8ModeScore rd, Vp8Residual resid
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();
Expand Down
29 changes: 15 additions & 14 deletions src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, WebpFeatures feat
private uint ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? image, ref ImageFrame<TPixel>? previousFrame, uint width, uint height, Color backgroundColor)
where TPixel : unmanaged, IPixel<TPixel>
{
AnimationFrameData frameData = AnimationFrameData.Parse(stream);
WebpFrameData frameData = WebpFrameData.Parse(stream);
long streamStartPosition = stream.Position;
Span<byte> buffer = stackalloc byte[4];

Expand All @@ -153,7 +153,7 @@ private uint ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? ima
}

WebpImageInfo? webpInfo = null;
WebpFeatures features = new WebpFeatures();
WebpFeatures features = new();
switch (chunkType)
{
case WebpChunkType.Vp8:
Expand All @@ -180,15 +180,15 @@ private uint ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? ima
{
image = new Image<TPixel>(this.configuration, (int)width, (int)height, backgroundColor.ToPixel<TPixel>(), this.metadata);

SetFrameMetadata(image.Frames.RootFrame.Metadata, frameData.Duration);
SetFrameMetadata(image.Frames.RootFrame.Metadata, frameData);

imageFrame = image.Frames.RootFrame;
}
else
{
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;
}
Expand All @@ -199,15 +199,15 @@ private uint ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? ima
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);
}

using Buffer2D<TPixel> decodedImage = this.DecodeImageData<TPixel>(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);
}
Expand All @@ -222,12 +222,13 @@ private uint ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? ima
/// Sets the frames metadata.
/// </summary>
/// <param name="meta">The metadata.</param>
/// <param name="duration">The frame duration.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SetFrameMetadata(ImageFrameMetadata meta, uint duration)
/// <param name="frameData">The frame data.</param>
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;
}

/// <summary>
Expand Down Expand Up @@ -256,24 +257,24 @@ private byte ReadAlphaData(BufferedReadStream stream)
/// <param name="frameData">The frame data.</param>
/// <param name="webpInfo">The webp information.</param>
/// <returns>A decoded image.</returns>
private Buffer2D<TPixel> DecodeImageData<TPixel>(AnimationFrameData frameData, WebpImageInfo webpInfo)
private Buffer2D<TPixel> DecodeImageData<TPixel>(WebpFrameData frameData, WebpImageInfo webpInfo)
where TPixel : unmanaged, IPixel<TPixel>
{
Image<TPixel> decodedImage = new Image<TPixel>((int)frameData.Width, (int)frameData.Height);
Image<TPixel> decodedImage = new((int)frameData.Width, (int)frameData.Height);

try
{
Buffer2D<TPixel> pixelBufferDecoded = decodedImage.GetRootFramePixelBuffer();
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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp;
/// <summary>
/// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas.
/// </summary>
internal enum AnimationBlendingMethod
public enum WebpBlendingMethod
{
/// <summary>
/// Use alpha blending. After disposing of the previous frame, render the current frame on the canvas using alpha-blending.
Expand Down
16 changes: 8 additions & 8 deletions src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public WebpDecoderCore(WebpDecoderOptions options)
public DecoderOptions Options { get; }

/// <inheritdoc/>
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);

/// <inheritdoc />
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
Expand All @@ -82,7 +82,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
Image<TPixel>? image = null;
try
{
ImageMetadata metadata = new ImageMetadata();
ImageMetadata metadata = new();
Span<byte> buffer = stackalloc byte[4];

uint fileSize = ReadImageHeader(stream, buffer);
Expand All @@ -91,7 +91,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
{
if (this.webImageInfo.Features is { Animation: true })
{
using WebpAnimationDecoder animationDecoder = new WebpAnimationDecoder(
using WebpAnimationDecoder animationDecoder = new(
this.memoryAllocator,
this.configuration,
this.maxFrames,
Expand All @@ -103,15 +103,15 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (this.webImageInfo.IsLossless)
{
WebpLosslessDecoder losslessDecoder = new WebpLosslessDecoder(
WebpLosslessDecoder losslessDecoder = new(
this.webImageInfo.Vp8LBitReader,
this.memoryAllocator,
this.configuration);
losslessDecoder.Decode(pixels, image.Width, image.Height);
}
else
{
WebpLossyDecoder lossyDecoder = new WebpLossyDecoder(
WebpLossyDecoder lossyDecoder = new(
this.webImageInfo.Vp8BitReader,
this.memoryAllocator,
this.configuration);
Expand Down Expand Up @@ -139,7 +139,7 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat
{
ReadImageHeader(stream, stackalloc byte[4]);

ImageMetadata metadata = new ImageMetadata();
ImageMetadata metadata = new();
using (this.webImageInfo = this.ReadVp8Info(stream, metadata, true))
{
return new ImageInfo(
Expand Down Expand Up @@ -185,7 +185,7 @@ private WebpImageInfo ReadVp8Info(BufferedReadStream stream, ImageMetadata metad
Span<byte> buffer = stackalloc byte[4];
WebpChunkType chunkType = WebpChunkParsingUtils.ReadChunkType(stream, buffer);

WebpFeatures features = new WebpFeatures();
WebpFeatures features = new();
switch (chunkType)
{
case WebpChunkType.Vp8:
Expand Down Expand Up @@ -392,7 +392,7 @@ private void ReadIccProfile(BufferedReadStream stream, ImageMetadata metadata, S
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp;
/// <summary>
/// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas.
/// </summary>
internal enum AnimationDisposalMethod
public enum WebpDisposalMethod
{
/// <summary>
/// Do not dispose. Leave the canvas as is.
Expand Down
8 changes: 4 additions & 4 deletions src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken

if (lossless)
{
using Vp8LEncoder encoder = new Vp8LEncoder(
using Vp8LEncoder encoder = new(
this.memoryAllocator,
this.configuration,
image.Width,
Expand All @@ -147,7 +147,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
{
foreach (ImageFrame<TPixel> imageFrame in image.Frames)
{
using Vp8LEncoder enc = new Vp8LEncoder(
using Vp8LEncoder enc = new(
this.memoryAllocator,
this.configuration,
image.Width,
Expand All @@ -171,7 +171,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
}
else
{
using Vp8Encoder encoder = new Vp8Encoder(
using Vp8Encoder encoder = new(
this.memoryAllocator,
this.configuration,
image.Width,
Expand All @@ -189,7 +189,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken

foreach (ImageFrame<TPixel> imageFrame in image.Frames)
{
using Vp8Encoder enc = new Vp8Encoder(
using Vp8Encoder enc = new(
this.memoryAllocator,
this.configuration,
image.Width,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace SixLabors.ImageSharp.Formats.Webp;

internal struct AnimationFrameData
internal struct WebpFrameData
{
/// <summary>
/// The animation chunk size.
Expand Down Expand Up @@ -46,23 +46,23 @@ internal struct AnimationFrameData
/// <summary>
/// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas.
/// </summary>
public AnimationBlendingMethod BlendingMethod;
public WebpBlendingMethod BlendingMethod;

/// <summary>
/// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas.
/// </summary>
public AnimationDisposalMethod DisposalMethod;
public WebpDisposalMethod DisposalMethod;

/// <summary>
/// Reads the animation frame header.
/// </summary>
/// <param name="stream">The stream to read from.</param>
/// <returns>Animation frame data.</returns>
public static AnimationFrameData Parse(BufferedReadStream stream)
public static WebpFrameData Parse(BufferedReadStream stream)
{
Span<byte> buffer = stackalloc byte[4];

AnimationFrameData data = new AnimationFrameData
WebpFrameData data = new()
{
DataSize = WebpChunkParsingUtils.ReadChunkSize(stream, buffer),

Expand All @@ -83,8 +83,8 @@ public static AnimationFrameData Parse(BufferedReadStream stream)
};

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;
}
Expand Down
Loading

0 comments on commit 8d2f255

Please sign in to comment.