|
|
@ -41,12 +41,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg |
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
private readonly byte[] emitBuffer = new byte[64]; |
|
|
private readonly byte[] emitBuffer = new byte[64]; |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// A buffer for reducing the number of stream writes when emitting Huffman tables. Max combined table lengths +
|
|
|
|
|
|
/// identifier.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly byte[] huffmanBuffer = new byte[179]; |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Gets or sets the subsampling method to use.
|
|
|
/// Gets or sets the subsampling method to use.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
@ -635,30 +629,40 @@ namespace SixLabors.ImageSharp.Formats.Jpeg |
|
|
markerlen += 1 + 16 + s.Values.Length; |
|
|
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<byte> huffmanBuffer = stackalloc byte[179]; |
|
|
|
|
|
byte* huffmanBufferPtr = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(huffmanBuffer)); |
|
|
|
|
|
|
|
|
this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen); |
|
|
this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen); |
|
|
for (int i = 0; i < specs.Length; i++) |
|
|
for (int i = 0; i < specs.Length; i++) |
|
|
{ |
|
|
{ |
|
|
ref HuffmanSpec spec = ref specs[i]; |
|
|
ref HuffmanSpec spec = ref specs[i]; |
|
|
|
|
|
|
|
|
int len = 0; |
|
|
int len = 0; |
|
|
|
|
|
|
|
|
fixed (byte* huffman = this.huffmanBuffer) |
|
|
// header
|
|
|
fixed (byte* count = spec.Count) |
|
|
huffmanBuffer[len++] = headers[i]; |
|
|
fixed (byte* values = spec.Values) |
|
|
|
|
|
{ |
|
|
|
|
|
huffman[len++] = headers[i]; |
|
|
|
|
|
|
|
|
|
|
|
for (int c = 0; c < spec.Count.Length; c++) |
|
|
// count
|
|
|
{ |
|
|
fixed (byte* countPtr = spec.Count) |
|
|
huffman[len++] = count[c]; |
|
|
{ |
|
|
} |
|
|
int countLen = spec.Count.Length; |
|
|
|
|
|
Unsafe.CopyBlockUnaligned(huffmanBufferPtr + len, countPtr, (uint)countLen); |
|
|
|
|
|
len += countLen; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (int v = 0; v < spec.Values.Length; v++) |
|
|
// values
|
|
|
{ |
|
|
fixed (byte* valuesPtr = spec.Values) |
|
|
huffman[len++] = values[v]; |
|
|
{ |
|
|
} |
|
|
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); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|