Skip to content

Commit c59a32e

Browse files
Merge pull request #1038 from SixLabors/js/huffman-decode-optimizations
Huffman decode optimizations
2 parents f64e141 + f4f0b14 commit c59a32e

File tree

4 files changed

+36
-20
lines changed

4 files changed

+36
-20
lines changed

src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public HuffmanScanBuffer(DoubleBufferedStreamReader stream)
5151
[MethodImpl(InliningOptions.ShortMethod)]
5252
public void CheckBits()
5353
{
54-
if (this.remainingBits < 16)
54+
if (this.remainingBits < JpegConstants.Huffman.MinBits)
5555
{
5656
this.FillBuffer();
5757
}
@@ -85,8 +85,8 @@ public void FillBuffer()
8585
{
8686
// Attempt to load at least the minimum number of required bits into the buffer.
8787
// We fail to do so only if we hit a marker or reach the end of the input stream.
88-
this.remainingBits += 48;
89-
this.data = (this.data << 48) | this.GetBytes();
88+
this.remainingBits += JpegConstants.Huffman.FetchBits;
89+
this.data = (this.data << JpegConstants.Huffman.FetchBits) | this.GetBytes();
9090
}
9191

9292
[MethodImpl(InliningOptions.ShortMethod)]
@@ -141,7 +141,7 @@ private static bool HasRestart(byte marker)
141141
private ulong GetBytes()
142142
{
143143
ulong temp = 0;
144-
for (int i = 0; i < 6; i++)
144+
for (int i = 0; i < JpegConstants.Huffman.FetchLoop; i++)
145145
{
146146
int b = this.ReadStream();
147147

src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ public void Configure()
8282

8383
// Figure C.1: make table of Huffman code length for each symbol
8484
int p = 0;
85-
for (int l = 1; l <= 16; l++)
85+
for (int j = 1; j <= 16; j++)
8686
{
87-
int i = this.Sizes[l];
87+
int i = this.Sizes[j];
8888
while (i-- != 0)
8989
{
90-
huffSize[p++] = (char)l;
90+
huffSize[p++] = (char)j;
9191
}
9292
}
9393

@@ -111,20 +111,19 @@ public void Configure()
111111

112112
// Figure F.15: generate decoding tables for bit-sequential decoding
113113
p = 0;
114-
for (int l = 1; l <= 16; l++)
114+
for (int j = 1; j <= 16; j++)
115115
{
116-
if (this.Sizes[l] != 0)
116+
if (this.Sizes[j] != 0)
117117
{
118-
int offset = p - (int)huffCode[p];
119-
this.ValOffset[l] = offset;
120-
p += this.Sizes[l];
121-
this.MaxCode[l] = huffCode[p - 1]; // Maximum code of length l
122-
this.MaxCode[l] <<= 64 - l; // Left justify
123-
this.MaxCode[l] |= (1ul << (64 - l)) - 1;
118+
this.ValOffset[j] = p - (int)huffCode[p];
119+
p += this.Sizes[j];
120+
this.MaxCode[j] = huffCode[p - 1]; // Maximum code of length l
121+
this.MaxCode[j] <<= JpegConstants.Huffman.RegisterSize - j; // Left justify
122+
this.MaxCode[j] |= (1ul << (JpegConstants.Huffman.RegisterSize - j)) - 1;
124123
}
125124
else
126125
{
127-
this.MaxCode[l] = 0;
126+
this.MaxCode[j] = 0;
128127
}
129128
}
130129

@@ -142,11 +141,12 @@ public void Configure()
142141
p = 0;
143142
for (int length = 1; length <= JpegConstants.Huffman.LookupBits; length++)
144143
{
144+
int jShift = JpegConstants.Huffman.LookupBits - length;
145145
for (int i = 1; i <= this.Sizes[length]; i++, p++)
146146
{
147147
// length = current code's length, p = its index in huffCode[] & Values[].
148148
// Generate left-justified code followed by all possible bit sequences
149-
int lookBits = (int)(huffCode[p] << (JpegConstants.Huffman.LookupBits - length));
149+
int lookBits = (int)(huffCode[p] << jShift);
150150
for (int ctr = 1 << (JpegConstants.Huffman.LookupBits - length); ctr > 0; ctr--)
151151
{
152152
this.LookaheadSize[lookBits] = (byte)length;

src/ImageSharp/Formats/Jpeg/JpegConstants.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
// Copyright (c) Six Labors and contributors.
1+
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

44
using System.Collections.Generic;
5+
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
56

67
namespace SixLabors.ImageSharp.Formats.Jpeg
78
{
@@ -249,6 +250,21 @@ internal static class Huffman
249250
/// </summary>
250251
public const int RegisterSize = 64;
251252

253+
/// <summary>
254+
/// The number of bits to fetch when filling the <see cref="HuffmanScanBuffer"/> buffer.
255+
/// </summary>
256+
public const int FetchBits = 48;
257+
258+
/// <summary>
259+
/// The number of times to read the input stream when filling the <see cref="HuffmanScanBuffer"/> buffer.
260+
/// </summary>
261+
public const int FetchLoop = FetchBits / 8;
262+
263+
/// <summary>
264+
/// The minimum number of bits allowed before by the <see cref="HuffmanScanBuffer"/> before fetching.
265+
/// </summary>
266+
public const int MinBits = RegisterSize - FetchBits;
267+
252268
/// <summary>
253269
/// If the next Huffman code is no more than this number of bits, we can obtain its length
254270
/// and the corresponding symbol directly from this tables.
@@ -266,4 +282,4 @@ internal static class Huffman
266282
public const int LookupSize = 1 << LookupBits;
267283
}
268284
}
269-
}
285+
}

src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public void Apply(ImageFrame<TPixel> source)
9494
}
9595

9696
/// <inheritdoc/>
97-
public virtual void Dispose()
97+
public void Dispose()
9898
{
9999
this.Dispose(true);
100100
GC.SuppressFinalize(this);

0 commit comments

Comments
 (0)