diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index c06f3f2a04..2ae3ae86bc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -727,6 +727,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// Table index. /// Code lengths. /// Code values. + /// The provided spare workspace memory, can be dirty. [MethodImpl(InliningOptions.ShortMethod)] public void BuildHuffmanTable(int type, int index, ReadOnlySpan codeLengths, ReadOnlySpan values, Span workspace) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index 7e69c4d94f..90a966d53f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -53,13 +53,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// The code lengths. /// The huffman values. - /// The spare workspace memory, must be provided by the caller. + /// The provided spare workspace memory, can be dirty. public HuffmanTable(ReadOnlySpan codeLengths, ReadOnlySpan values, Span workspace) { Unsafe.CopyBlockUnaligned(ref this.Values[0], ref MemoryMarshal.GetReference(values), (uint)values.Length); - Span huffCode = workspace; - // Generate codes uint code = 0; int si = 1; @@ -69,7 +67,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int count = codeLengths[i]; for (int j = 0; j < count; j++) { - huffCode[p++] = code; + workspace[p++] = code; code++; } @@ -94,9 +92,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { if (codeLengths[j] != 0) { - this.ValOffset[j] = p - (int)huffCode[p]; + this.ValOffset[j] = p - (int)workspace[p]; p += codeLengths[j]; - this.MaxCode[j] = huffCode[p - 1]; // Maximum code of length l + this.MaxCode[j] = workspace[p - 1]; // Maximum code of length l this.MaxCode[j] <<= JpegConstants.Huffman.RegisterSize - j; // Left justify this.MaxCode[j] |= (1ul << (JpegConstants.Huffman.RegisterSize - j)) - 1; } @@ -125,7 +123,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { // length = current code's length, p = its index in huffCode[] & Values[]. // Generate left-justified code followed by all possible bit sequences - int lookBits = (int)(huffCode[p] << jShift); + int lookBits = (int)(workspace[p] << jShift); for (int ctr = 1 << (JpegConstants.Huffman.LookupBits - length); ctr > 0; ctr--) { this.LookaheadSize[lookBits] = (byte)length; diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 4c6772a6f6..a2cccc37f5 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -1095,15 +1095,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The remaining bytes in the segment block. private void ProcessDefineHuffmanTablesMarker(BufferedReadStream stream, int remaining) { - const int codeLengthsByteSize = 16; + const int codeLengthsByteSize = 17; const int codeValuesMaxByteSize = 256; - const int tableWorkspaceByteSize = 257 * sizeof(uint); + const int tableWorkspaceByteSize = 256 * sizeof(uint); const int totalBufferSize = codeLengthsByteSize + codeValuesMaxByteSize + tableWorkspaceByteSize; int length = remaining; - using (IMemoryOwner huffmanData = this.Configuration.MemoryAllocator.Allocate(17)) + using (IMemoryOwner buffer = this.Configuration.MemoryAllocator.Allocate(totalBufferSize)) { - Span huffmanDataSpan = huffmanData.GetSpan(); + Span bufferSpan = buffer.GetSpan(); + Span huffmanLegthsSpan = buffer.Slice(0, codeLengthsByteSize); + Span huffmanValuesSpan = buffer.Slice(codeLengthsByteSize, codeValuesMaxByteSize); + Span tableWorkspace = MemoryMarshal.Cast(buffer.Slice(codeLengthsByteSize + codeValuesMaxByteSize)); + for (int i = 2; i < remaining;) { byte huffmanTableSpec = (byte)stream.ReadByte(); @@ -1122,12 +1126,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg JpegThrowHelper.ThrowInvalidImageContentException($"Bad huffman table index: {tableIndex}."); } - stream.Read(huffmanDataSpan, 1, 16); + stream.Read(huffmanLegthsSpan, 1, 16); int codeLengthSum = 0; for (int j = 1; j < 17; j++) { - codeLengthSum += huffmanDataSpan[j]; + codeLengthSum += huffmanLegthsSpan[j]; } length -= 17; @@ -1137,20 +1141,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg JpegThrowHelper.ThrowInvalidImageContentException("Huffman table has excessive length."); } - using (IMemoryOwner huffmanValues = this.Configuration.MemoryAllocator.Allocate(256, AllocationOptions.Clean)) - { - Span huffmanValuesSpan = huffmanValues.GetSpan(); - stream.Read(huffmanValuesSpan, 0, codeLengthSum); + stream.Read(huffmanValuesSpan, 0, codeLengthSum); - i += 17 + codeLengthSum; + i += 17 + codeLengthSum; - this.scanDecoder.BuildHuffmanTable( - tableType, - tableIndex, - huffmanDataSpan, - huffmanValuesSpan, - stackalloc uint[257]); - } + this.scanDecoder.BuildHuffmanTable( + tableType, + tableIndex, + huffmanLegthsSpan, + huffmanValuesSpan.Slice(0, codeLengthSum), + tableWorkspace); } } }