Browse Source

Merge pull request #1038 from SixLabors/js/huffman-decode-optimizations

Huffman decode optimizations
pull/1041/head
James Jackson-South 6 years ago
committed by GitHub
parent
commit
c59a32e505
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs
  2. 26
      src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs
  3. 20
      src/ImageSharp/Formats/Jpeg/JpegConstants.cs
  4. 2
      src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs

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

@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
[MethodImpl(InliningOptions.ShortMethod)]
public void CheckBits()
{
if (this.remainingBits < 16)
if (this.remainingBits < JpegConstants.Huffman.MinBits)
{
this.FillBuffer();
}
@ -85,8 +85,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
// Attempt to load at least the minimum number of required bits into the buffer.
// We fail to do so only if we hit a marker or reach the end of the input stream.
this.remainingBits += 48;
this.data = (this.data << 48) | this.GetBytes();
this.remainingBits += JpegConstants.Huffman.FetchBits;
this.data = (this.data << JpegConstants.Huffman.FetchBits) | this.GetBytes();
}
[MethodImpl(InliningOptions.ShortMethod)]
@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private ulong GetBytes()
{
ulong temp = 0;
for (int i = 0; i < 6; i++)
for (int i = 0; i < JpegConstants.Huffman.FetchLoop; i++)
{
int b = this.ReadStream();

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

@ -82,12 +82,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Figure C.1: make table of Huffman code length for each symbol
int p = 0;
for (int l = 1; l <= 16; l++)
for (int j = 1; j <= 16; j++)
{
int i = this.Sizes[l];
int i = this.Sizes[j];
while (i-- != 0)
{
huffSize[p++] = (char)l;
huffSize[p++] = (char)j;
}
}
@ -111,20 +111,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Figure F.15: generate decoding tables for bit-sequential decoding
p = 0;
for (int l = 1; l <= 16; l++)
for (int j = 1; j <= 16; j++)
{
if (this.Sizes[l] != 0)
if (this.Sizes[j] != 0)
{
int offset = p - (int)huffCode[p];
this.ValOffset[l] = offset;
p += this.Sizes[l];
this.MaxCode[l] = huffCode[p - 1]; // Maximum code of length l
this.MaxCode[l] <<= 64 - l; // Left justify
this.MaxCode[l] |= (1ul << (64 - l)) - 1;
this.ValOffset[j] = p - (int)huffCode[p];
p += this.Sizes[j];
this.MaxCode[j] = huffCode[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;
}
else
{
this.MaxCode[l] = 0;
this.MaxCode[j] = 0;
}
}
@ -142,11 +141,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
p = 0;
for (int length = 1; length <= JpegConstants.Huffman.LookupBits; length++)
{
int jShift = JpegConstants.Huffman.LookupBits - length;
for (int i = 1; i <= this.Sizes[length]; i++, p++)
{
// 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] << (JpegConstants.Huffman.LookupBits - length));
int lookBits = (int)(huffCode[p] << jShift);
for (int ctr = 1 << (JpegConstants.Huffman.LookupBits - length); ctr > 0; ctr--)
{
this.LookaheadSize[lookBits] = (byte)length;

20
src/ImageSharp/Formats/Jpeg/JpegConstants.cs

@ -1,7 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
namespace SixLabors.ImageSharp.Formats.Jpeg
{
@ -249,6 +250,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary>
public const int RegisterSize = 64;
/// <summary>
/// The number of bits to fetch when filling the <see cref="HuffmanScanBuffer"/> buffer.
/// </summary>
public const int FetchBits = 48;
/// <summary>
/// The number of times to read the input stream when filling the <see cref="HuffmanScanBuffer"/> buffer.
/// </summary>
public const int FetchLoop = FetchBits / 8;
/// <summary>
/// The minimum number of bits allowed before by the <see cref="HuffmanScanBuffer"/> before fetching.
/// </summary>
public const int MinBits = RegisterSize - FetchBits;
/// <summary>
/// If the next Huffman code is no more than this number of bits, we can obtain its length
/// and the corresponding symbol directly from this tables.
@ -266,4 +282,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public const int LookupSize = 1 << LookupBits;
}
}
}
}

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

@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
/// <inheritdoc/>
public virtual void Dispose()
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);

Loading…
Cancel
Save