From 9408737cfcd3b166f43f9cd13d71657abff0ba6b Mon Sep 17 00:00:00 2001 From: Steve Temple Date: Sat, 25 Jul 2020 23:16:46 +0100 Subject: [PATCH 1/2] Added Clone and Resize to Vp8LBitWriter Also looked at some TODOs in Vp8LEncoder --- .../Formats/WebP/BitWriter/Vp8LBitWriter.cs | 53 +++++++++++++++---- .../Formats/WebP/Lossless/Vp8LEncoder.cs | 17 +++++- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs index 9ff4576485..7428c8bcce 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. @@ -99,11 +109,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 +118,37 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter this.used -= WriterBits; } - private bool BitWriterResize(int extraSize) + private void BitWriterResize(int extraSize) + { + 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; + } + + public Vp8LBitWriter Clone() { - // TODO: resize buffer - return true; + 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); } } } 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; } /// From 231f19b13d9989b2965332f859ed0609b661d898 Mon Sep 17 00:00:00 2001 From: Steve Temple Date: Sat, 25 Jul 2020 23:22:47 +0100 Subject: [PATCH 2/2] Move public method above privates in Vp8LBitWriter --- .../Formats/WebP/BitWriter/Vp8LBitWriter.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs index 7428c8bcce..a3e35448be 100644 --- a/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs +++ b/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs @@ -100,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. /// @@ -143,12 +150,5 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter this.end = this.buffer.Length; } - - 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); - } } }