diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
index f5dc1c79fe..79f0d3022a 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
@@ -41,12 +41,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
///
private readonly byte[] emitBuffer = new byte[64];
- ///
- /// A buffer for reducing the number of stream writes when emitting Huffman tables. Max combined table lengths +
- /// identifier.
- ///
- private readonly byte[] huffmanBuffer = new byte[179];
-
///
/// Gets or sets the subsampling method to use.
///
@@ -635,30 +629,40 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
markerlen += 1 + 16 + s.Values.Length;
}
+ // TODO: this magic constant (array size) should be defined by HuffmanSpec class
+ // This is a one-time call which can be stackalloc'ed or allocated directly in memory as method local array
+ // Allocation here would be better for GC so it won't live for entire encoding process
+ // TODO: if this is allocated on the heap - pin it right here or following copy code will corrupt memory
+ Span huffmanBuffer = stackalloc byte[179];
+ byte* huffmanBufferPtr = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(huffmanBuffer));
+
this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen);
for (int i = 0; i < specs.Length; i++)
{
ref HuffmanSpec spec = ref specs[i];
+
int len = 0;
- fixed (byte* huffman = this.huffmanBuffer)
- fixed (byte* count = spec.Count)
- fixed (byte* values = spec.Values)
- {
- huffman[len++] = headers[i];
+ // header
+ huffmanBuffer[len++] = headers[i];
- for (int c = 0; c < spec.Count.Length; c++)
- {
- huffman[len++] = count[c];
- }
+ // count
+ fixed (byte* countPtr = spec.Count)
+ {
+ int countLen = spec.Count.Length;
+ Unsafe.CopyBlockUnaligned(huffmanBufferPtr + len, countPtr, (uint)countLen);
+ len += countLen;
+ }
- for (int v = 0; v < spec.Values.Length; v++)
- {
- huffman[len++] = values[v];
- }
+ // values
+ fixed (byte* valuesPtr = spec.Values)
+ {
+ int valuesLen = spec.Values.Length;
+ Unsafe.CopyBlockUnaligned(huffmanBufferPtr + len, valuesPtr, (uint)valuesLen);
+ len += valuesLen;
}
- this.outputStream.Write(this.huffmanBuffer, 0, len);
+ this.outputStream.Write(huffmanBuffer, 0, len);
}
}