diff --git a/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs
index 9ff4576485..a3e35448be 100644
--- a/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs
+++ b/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs
@@ -45,14 +45,24 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
private int end;
- private bool error;
-
public Vp8LBitWriter(int expectedSize)
{
this.buffer = new byte[expectedSize];
this.end = this.buffer.Length;
}
+ ///
+ /// Initializes a new instance of the class.
+ /// Used internally for cloning
+ ///
+ private Vp8LBitWriter(byte[] buffer, ulong bits, int used, int cur)
+ {
+ this.buffer = buffer;
+ this.bits = bits;
+ this.used = used;
+ this.cur = cur;
+ }
+
///
/// This function writes bits into bytes in increasing addresses (little endian),
/// and within a byte least-significant-bit first. This function can write up to 32 bits in one go.
@@ -90,6 +100,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
return this.cur + ((this.used + 7) >> 3);
}
+ public Vp8LBitWriter Clone()
+ {
+ byte[] clonedBuffer = new byte[this.buffer.Length];
+ Buffer.BlockCopy(this.buffer, 0, clonedBuffer, 0, this.cur);
+ return new Vp8LBitWriter(clonedBuffer, this.bits, this.used, this.cur);
+ }
+
///
/// Internal function for PutBits flushing 32 bits from the written state.
///
@@ -99,11 +116,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
if (this.cur + WriterBytes > this.end)
{
var extraSize = (this.end - this.cur) + MinExtraSize;
- if (!this.BitWriterResize(extraSize))
- {
- this.error = true;
- return;
- }
+ this.BitWriterResize(extraSize);
}
BinaryPrimitives.WriteUInt64LittleEndian(this.buffer.AsSpan(this.cur), this.bits);
@@ -112,10 +125,30 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
this.used -= WriterBits;
}
- private bool BitWriterResize(int extraSize)
+ private void BitWriterResize(int extraSize)
{
- // TODO: resize buffer
- return true;
+ int maxBytes = this.end + this.buffer.Length;
+ int sizeRequired = this.cur + extraSize;
+
+ if (maxBytes > 0 && sizeRequired < maxBytes)
+ {
+ return;
+ }
+
+ int newSize = (3 * maxBytes) >> 1;
+ if (newSize < sizeRequired)
+ {
+ newSize = sizeRequired;
+ }
+
+ // make new size multiple of 1k
+ newSize = ((newSize >> 10) + 1) << 10;
+ if (this.cur > 0)
+ {
+ Array.Resize(ref this.buffer, newSize);
+ }
+
+ this.end = this.buffer.Length;
}
}
}
diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
index aac3bd52ed..1663c32dd2 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
@@ -318,8 +318,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// Calculate backward references from ARGB image.
BackwardReferenceEncoder.HashChainFill(hashChain, bgra, quality, width, height);
- // TODO: BitWriterInit(&bw_best, 0)
- // BitWriterClone(bw, &bw_best))
+ Vp8LBitWriter bitWriterBest = null;
+ if (lz77sTypesToTrySize > 1)
+ {
+ bitWriterBest = this.bitWriter.Clone();
+ }
for (int lz77sIdx = 0; lz77sIdx < lz77sTypesToTrySize; lz77sIdx++)
{
@@ -329,6 +332,8 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// two as a temporary for later usage.
Vp8LBackwardRefs refsTmp = refsArray[refsBest.Equals(refsArray[0]) ? 1 : 0];
+ // TODO: this.bitWriter.Reset();
+
var tmpHisto = new Vp8LHistogram(cacheBits);
var histogramImage = new List(histogramImageXySize);
for (int i = 0; i < histogramImageXySize; i++)
@@ -414,7 +419,15 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
this.StoreImageToBitMask(width, histogramBits, refsBest, histogramSymbols, huffmanCodes);
// TODO: Keep track of the smallest image so far.
+
+ if (bitWriterBest != null && this.bitWriter.NumBytes() < bitWriterBest.NumBytes())
+ {
+ // TODO : This was done in the reference by swapping references, this will be slower
+ bitWriterBest = this.bitWriter.Clone();
+ }
}
+
+ this.bitWriter = bitWriterBest;
}
///