diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
index 10eda9c5a..42a683539 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
@@ -41,10 +41,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
private const int BytesPerCodingUnit = 256 * 3;
- ///
- /// Number of filled bytes in buffer
- ///
- private int emitLen = 0;
+ private int emitWriteIndex = (EmitBufferSizeInBytes / 4);
///
/// Emmited bits 'micro buffer' before being transfered to the .
@@ -123,14 +120,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref chrominanceQuantTable,
ref unzig);
- if (this.emitLen + (BytesPerCodingUnit / 4) > EmitBufferSizeInBytes / 4)
+ if (this.emitWriteIndex < this.emitBuffer.Length / 2)
{
this.WriteToStream();
}
}
}
- this.FlushInternalBuffer();
+ this.EmitFinalBits();
}
///
@@ -311,6 +308,34 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
return dc;
}
+ [MethodImpl(InliningOptions.ShortMethod)]
+ private void EmitFinalBits()
+ {
+ // Bytes count we want to write to the output stream
+ int valuableBytesCount = (int)Numerics.DivideCeil((uint)this.bitCount, 8);
+
+ // Padding all 4 bytes with 1's while not corrupting initial bits stored in accumulatedBits
+ uint packedBytes = (this.accumulatedBits | (uint.MaxValue >> this.bitCount)) >> ((4 - valuableBytesCount) * 8);
+
+ // 2x size due to possible stuff bytes, max out to 8
+ Span tempBuffer = stackalloc byte[valuableBytesCount * 2];
+
+ // Write bytes to temporal buffer
+ int writeCount = 0;
+ for (int i = 0; i < valuableBytesCount; i++)
+ {
+ byte value = (byte)(packedBytes >> (i * 8));
+ tempBuffer[writeCount++] = value;
+ if (value == 0xff)
+ {
+ tempBuffer[writeCount++] = 0;
+ }
+ }
+
+ // Write temporal buffer to the output stream
+ this.target.Write(tempBuffer, 0, writeCount);
+ }
+
///
/// Emits the least significant count of bits to the stream write buffer.
/// The precondition is bits
@@ -332,7 +357,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
if (count >= 32)
{
- this.emitBuffer[this.emitLen++] = this.accumulatedBits;
+ this.emitBuffer[--this.emitWriteIndex] = this.accumulatedBits;
this.accumulatedBits = correctedBits << (32 - this.bitCount);
count -= 32;
@@ -514,7 +539,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
Span emitBytes = MemoryMarshal.AsBytes(this.emitBuffer.AsSpan());
int writeIdx = 0;
- for (int i = 0; i < this.emitLen * 4; i++)
+ int start = emitBytes.Length - 1;
+ int end = (this.emitWriteIndex * 4) - 1;
+ for (int i = start; i > end; i--)
{
byte value = emitBytes[i];
this.streamWriteBuffer[writeIdx++] = value;
@@ -525,7 +552,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
}
this.target.Write(this.streamWriteBuffer, 0, writeIdx);
- this.emitLen = 0;
+ this.emitWriteIndex = this.emitBuffer.Length;
}
}
}