Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Poker-sang committed Oct 22, 2023
1 parent 6f52a0d commit 682218a
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 56 deletions.
9 changes: 7 additions & 2 deletions src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.

using System.Buffers.Binary;
using System.Drawing;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
Expand Down Expand Up @@ -181,7 +180,7 @@ protected void WriteAnimationParameter(Stream stream, uint background, ushort lo
/// <param name="stream">The stream to write to.</param>
/// <param name="animation">Animation frame data.</param>
/// <param name="data">Frame data.</param>
protected void WriteAnimationFrame(Stream stream, AnimationFrameData animation, byte[] data)
protected void WriteAnimationFrame(Stream stream, AnimationFrameData animation, Span<byte> data)
{
uint size = AnimationFrameData.HeaderSize + (uint)data.Length;
Span<byte> buf = this.scratchBuffer.Span[..4];
Expand Down Expand Up @@ -260,6 +259,12 @@ protected void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfi
flags |= 8;
}

// if (isAnimated)
// {
// // Set animated flag.
// flags |= 2;
// }

Check failure on line 266 in src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net7.0, 7.0.x, true, -x64, false)

Single-line comments should not be followed by blank line (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md)

Check failure on line 266 in src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net7.0, 7.0.x, true, -x64, false)

Single-line comments should not be followed by blank line (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md)

Check failure on line 266 in src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net6.0, 6.0.x, -x64, false)

Single-line comments should not be followed by blank line (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md)

Check failure on line 266 in src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net6.0, 6.0.x, -x64, false)

Single-line comments should not be followed by blank line (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md)

if (xmpProfile != null)
{
// Set xmp bit.
Expand Down
104 changes: 52 additions & 52 deletions src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public int PutCoeffs(int ctx, Vp8Residual residual)
else
{
this.PutBit(v >= 9, 165);
this.PutBit(!((v & 1) != 0), 145);
this.PutBit((v & 1) == 0, 145);
}
}
else
Expand Down Expand Up @@ -462,7 +462,7 @@ public void WriteEncodedImageToStream(
Vp8BitWriter bitWriterPartZero = new(expectedSize, this.enc);

// Partition #0 with header and partition sizes.
uint size0 = this.GeneratePartition0(bitWriterPartZero);
uint size0 = bitWriterPartZero.GeneratePartition0();

uint vp8Size = WebpConstants.Vp8FrameHeaderSize + size0;
vp8Size += numBytes;
Expand Down Expand Up @@ -495,98 +495,98 @@ public void WriteEncodedImageToStream(
}
}

private uint GeneratePartition0(Vp8BitWriter bitWriter)
private uint GeneratePartition0()
{
bitWriter.PutBitUniform(0); // colorspace
bitWriter.PutBitUniform(0); // clamp type
this.PutBitUniform(0); // colorspace
this.PutBitUniform(0); // clamp type

this.WriteSegmentHeader(bitWriter);
this.WriteFilterHeader(bitWriter);
this.WriteSegmentHeader();
this.WriteFilterHeader();

bitWriter.PutBits(0, 2);
this.PutBits(0, 2);

this.WriteQuant(bitWriter);
bitWriter.PutBitUniform(0);
this.WriteProbas(bitWriter);
this.CodeIntraModes(bitWriter);
this.WriteQuant();
this.PutBitUniform(0);
this.WriteProbas();
this.CodeIntraModes();

bitWriter.Finish();
this.Finish();

return (uint)bitWriter.NumBytes();
return (uint)this.NumBytes();
}

private void WriteSegmentHeader(Vp8BitWriter bitWriter)
private void WriteSegmentHeader()
{
Vp8EncSegmentHeader hdr = this.enc.SegmentHeader;
Vp8EncProba proba = this.enc.Proba;
if (bitWriter.PutBitUniform(hdr.NumSegments > 1 ? 1 : 0) != 0)
if (this.PutBitUniform(hdr.NumSegments > 1 ? 1 : 0) != 0)
{
// We always 'update' the quant and filter strength values.
int updateData = 1;
bitWriter.PutBitUniform(hdr.UpdateMap ? 1 : 0);
if (bitWriter.PutBitUniform(updateData) != 0)
this.PutBitUniform(hdr.UpdateMap ? 1 : 0);
if (this.PutBitUniform(updateData) != 0)
{
// We always use absolute values, not relative ones.
bitWriter.PutBitUniform(1); // (segment_feature_mode = 1. Paragraph 9.3.)
this.PutBitUniform(1); // (segment_feature_mode = 1. Paragraph 9.3.)
for (int s = 0; s < WebpConstants.NumMbSegments; ++s)
{
bitWriter.PutSignedBits(this.enc.SegmentInfos[s].Quant, 7);
this.PutSignedBits(this.enc.SegmentInfos[s].Quant, 7);
}

for (int s = 0; s < WebpConstants.NumMbSegments; ++s)
{
bitWriter.PutSignedBits(this.enc.SegmentInfos[s].FStrength, 6);
this.PutSignedBits(this.enc.SegmentInfos[s].FStrength, 6);
}
}

if (hdr.UpdateMap)
{
for (int s = 0; s < 3; ++s)
{
if (bitWriter.PutBitUniform(proba.Segments[s] != 255 ? 1 : 0) != 0)
if (this.PutBitUniform(proba.Segments[s] != 255 ? 1 : 0) != 0)
{
bitWriter.PutBits(proba.Segments[s], 8);
this.PutBits(proba.Segments[s], 8);
}
}
}
}
}

private void WriteFilterHeader(Vp8BitWriter bitWriter)
private void WriteFilterHeader()
{
Vp8FilterHeader hdr = this.enc.FilterHeader;
bool useLfDelta = hdr.I4x4LfDelta != 0;
bitWriter.PutBitUniform(hdr.Simple ? 1 : 0);
bitWriter.PutBits((uint)hdr.FilterLevel, 6);
bitWriter.PutBits((uint)hdr.Sharpness, 3);
if (bitWriter.PutBitUniform(useLfDelta ? 1 : 0) != 0)
this.PutBitUniform(hdr.Simple ? 1 : 0);
this.PutBits((uint)hdr.FilterLevel, 6);
this.PutBits((uint)hdr.Sharpness, 3);
if (this.PutBitUniform(useLfDelta ? 1 : 0) != 0)
{
// '0' is the default value for i4x4LfDelta at frame #0.
bool needUpdate = hdr.I4x4LfDelta != 0;
if (bitWriter.PutBitUniform(needUpdate ? 1 : 0) != 0)
if (this.PutBitUniform(needUpdate ? 1 : 0) != 0)
{
// we don't use refLfDelta => emit four 0 bits.
bitWriter.PutBits(0, 4);
this.PutBits(0, 4);

// we use modeLfDelta for i4x4
bitWriter.PutSignedBits(hdr.I4x4LfDelta, 6);
bitWriter.PutBits(0, 3); // all others unused.
this.PutSignedBits(hdr.I4x4LfDelta, 6);
this.PutBits(0, 3); // all others unused.
}
}
}

// Nominal quantization parameters
private void WriteQuant(Vp8BitWriter bitWriter)
private void WriteQuant()
{
bitWriter.PutBits((uint)this.enc.BaseQuant, 7);
bitWriter.PutSignedBits(this.enc.DqY1Dc, 4);
bitWriter.PutSignedBits(this.enc.DqY2Dc, 4);
bitWriter.PutSignedBits(this.enc.DqY2Ac, 4);
bitWriter.PutSignedBits(this.enc.DqUvDc, 4);
bitWriter.PutSignedBits(this.enc.DqUvAc, 4);
this.PutBits((uint)this.enc.BaseQuant, 7);
this.PutSignedBits(this.enc.DqY1Dc, 4);
this.PutSignedBits(this.enc.DqY2Dc, 4);
this.PutSignedBits(this.enc.DqY2Ac, 4);
this.PutSignedBits(this.enc.DqUvDc, 4);
this.PutSignedBits(this.enc.DqUvAc, 4);
}

private void WriteProbas(Vp8BitWriter bitWriter)
private void WriteProbas()
{
Vp8EncProba probas = this.enc.Proba;
for (int t = 0; t < WebpConstants.NumTypes; ++t)
Expand All @@ -599,25 +599,25 @@ private void WriteProbas(Vp8BitWriter bitWriter)
{
byte p0 = probas.Coeffs[t][b].Probabilities[c].Probabilities[p];
bool update = p0 != WebpLookupTables.DefaultCoeffsProba[t, b, c, p];
if (bitWriter.PutBit(update, WebpLookupTables.CoeffsUpdateProba[t, b, c, p]))
if (this.PutBit(update, WebpLookupTables.CoeffsUpdateProba[t, b, c, p]))
{
bitWriter.PutBits(p0, 8);
this.PutBits(p0, 8);
}
}
}
}
}

if (bitWriter.PutBitUniform(probas.UseSkipProba ? 1 : 0) != 0)
if (this.PutBitUniform(probas.UseSkipProba ? 1 : 0) != 0)
{
bitWriter.PutBits(probas.SkipProba, 8);
this.PutBits(probas.SkipProba, 8);
}
}

// Writes the partition #0 modes (that is: all intra modes)
private void CodeIntraModes(Vp8BitWriter bitWriter)
private void CodeIntraModes()
{
var it = new Vp8EncIterator(this.enc.YTop, this.enc.UvTop, this.enc.Nz, this.enc.MbInfo, this.enc.Preds, this.enc.TopDerr, this.enc.Mbw, this.enc.Mbh);
Vp8EncIterator it = new(this.enc);
int predsWidth = this.enc.PredsWidth;

do
Expand All @@ -627,18 +627,18 @@ private void CodeIntraModes(Vp8BitWriter bitWriter)
Span<byte> preds = it.Preds.AsSpan(predIdx);
if (this.enc.SegmentHeader.UpdateMap)
{
bitWriter.PutSegment(mb.Segment, this.enc.Proba.Segments);
this.PutSegment(mb.Segment, this.enc.Proba.Segments);
}

if (this.enc.Proba.UseSkipProba)
{
bitWriter.PutBit(mb.Skip, this.enc.Proba.SkipProba);
this.PutBit(mb.Skip, this.enc.Proba.SkipProba);
}

if (bitWriter.PutBit(mb.MacroBlockType != 0, 145))
if (this.PutBit(mb.MacroBlockType != 0, 145))
{
// i16x16
bitWriter.PutI16Mode(preds[0]);
this.PutI16Mode(preds[0]);
}
else
{
Expand All @@ -649,15 +649,15 @@ private void CodeIntraModes(Vp8BitWriter bitWriter)
for (int x = 0; x < 4; x++)
{
byte[] probas = WebpLookupTables.ModesProba[topPred[x], left];
left = bitWriter.PutI4Mode(it.Preds[predIdx + x], probas);
left = this.PutI4Mode(it.Preds[predIdx + x], probas);
}

topPred = it.Preds.AsSpan(predIdx);
predIdx += predsWidth;
}
}

bitWriter.PutUvMode(mb.UvMode);
this.PutUvMode(mb.UvMode);
}
while (it.Next());
}
Expand Down
5 changes: 5 additions & 0 deletions src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ internal class Vp8EncIterator

private int uvTopIdx;

public Vp8EncIterator(Vp8Encoder enc)
: this(enc.YTop, enc.UvTop, enc.Nz, enc.MbInfo, enc.Preds, enc.TopDerr, enc.Mbw, enc.Mbh)
{
}

public Vp8EncIterator(byte[] yTop, byte[] uvTop, uint[] nz, Vp8MacroBlockInfo[] mb, byte[] preds, sbyte[] topDerr, int mbw, int mbh)
{
this.YTop = yTop;
Expand Down
4 changes: 2 additions & 2 deletions src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
int yStride = width;
int uvStride = (yStride + 1) >> 1;

Vp8EncIterator it = new(this.YTop, this.UvTop, this.Nz, this.MbInfo, this.Preds, this.TopDerr, this.Mbw, this.Mbh);
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 Down Expand Up @@ -520,7 +520,7 @@ 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(this.YTop, this.UvTop, this.Nz, this.MbInfo, this.Preds, this.TopDerr, this.Mbw, this.Mbh);
Vp8EncIterator it = new(this);
long size = 0;
long sizeP0 = 0;
long distortion = 0;
Expand Down
5 changes: 5 additions & 0 deletions src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ private uint ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? ima
features.AlphaChunkHeader = alphaChunkHeader;
break;
case WebpChunkType.Vp8L:
if (hasAlpha)
{
WebpThrowHelper.ThrowNotSupportedException("Alpha channel is not supported for lossless webp images.");
}

webpInfo = WebpChunkParsingUtils.ReadVp8LHeader(this.memoryAllocator, stream, buffer, features);
break;
default:
Expand Down

0 comments on commit 682218a

Please sign in to comment.