diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
index 778d6ccd83..10eda9c5a3 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
@@ -1,8 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
+using System;
using System.IO;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
@@ -33,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
///
/// A buffer for reducing the number of stream writes when emitting Huffman tables.
///
- private readonly byte[] emitBuffer = new byte[EmitBufferSizeInBytes];
+ private readonly uint[] emitBuffer = new uint[EmitBufferSizeInBytes / 4];
private readonly byte[] streamWriteBuffer = new byte[EmitBufferSizeInBytes * 2];
@@ -47,7 +49,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
///
/// Emmited bits 'micro buffer' before being transfered to the .
///
- private int accumulatedBits;
+ private uint accumulatedBits;
///
/// Number of jagged bits stored in
@@ -121,7 +123,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
ref chrominanceQuantTable,
ref unzig);
- if (this.emitLen + BytesPerCodingUnit > EmitBufferSizeInBytes)
+ if (this.emitLen + (BytesPerCodingUnit / 4) > EmitBufferSizeInBytes / 4)
{
this.WriteToStream();
}
@@ -320,27 +322,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// The packed bits.
/// The number of bits
[MethodImpl(InliningOptions.ShortMethod)]
- private void Emit(int bits, int count)
+ private void Emit(uint bits, int count)
{
+ uint correctedBits = bits << (32 - count);
+
+ this.accumulatedBits |= correctedBits >> this.bitCount;
+
count += this.bitCount;
- bits <<= 32 - count;
- bits |= this.accumulatedBits;
- // Only write if more than 8 bits.
- if (count >= 8)
+ if (count >= 32)
{
- // Track length
- while (count >= 8)
- {
- byte b = (byte)(bits >> 24);
- this.emitBuffer[this.emitLen++] = b;
+ this.emitBuffer[this.emitLen++] = this.accumulatedBits;
+ this.accumulatedBits = correctedBits << (32 - this.bitCount);
- bits <<= 8;
- count -= 8;
- }
+ count -= 32;
}
- this.accumulatedBits = bits;
this.bitCount = count;
}
@@ -353,7 +350,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
private void EmitHuff(int[] table, int value)
{
int x = table[value];
- this.Emit(x >> 8, x & 0xff);
+ this.Emit((uint)x >> 8, x & 0xff);
}
[MethodImpl(InliningOptions.ShortMethod)]
@@ -372,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.EmitHuff(table, bt);
if (bt > 0)
{
- this.Emit(b & ((1 << bt) - 1), bt);
+ this.Emit((uint)(b & ((1 << bt) - 1)), bt);
}
}
@@ -396,7 +393,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
int bt = GetHuffmanEncodingLength((uint)a);
this.EmitHuff(table, (runLength << 4) | bt);
- this.Emit(b & ((1 << bt) - 1), bt);
+ this.Emit((uint)(b & ((1 << bt) - 1)), bt);
}
///
@@ -406,12 +403,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
private void FlushInternalBuffer()
{
// pad last byte with 1's
- int padBitsCount = 8 - (this.bitCount % 8);
- if (padBitsCount != 0)
- {
- this.Emit((1 << padBitsCount) - 1, padBitsCount);
- this.target.Write(this.emitBuffer, 0, this.emitLen);
- }
+ //int padBitsCount = 8 - (this.bitCount % 8);
+ //if (padBitsCount != 0)
+ //{
+ // this.Emit((1 << padBitsCount) - 1, padBitsCount);
+ // this.target.Write(this.emitBuffer, 0, this.emitLen);
+ //}
}
///
@@ -514,10 +511,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
[MethodImpl(InliningOptions.ShortMethod)]
private void WriteToStream()
{
+ Span emitBytes = MemoryMarshal.AsBytes(this.emitBuffer.AsSpan());
+
int writeIdx = 0;
- for (int i = 0; i < this.emitLen; i++)
+ for (int i = 0; i < this.emitLen * 4; i++)
{
- byte value = this.emitBuffer[i];
+ byte value = emitBytes[i];
this.streamWriteBuffer[writeIdx++] = value;
if (value == 0xff)
{