Browse Source

Use properties

af/merge-core
James Jackson-South 9 years ago
parent
commit
8e4cdc732a
  1. 125
      src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTable.cs
  2. 8
      src/ImageSharp/Formats/Jpeg/Port/Components/ScanDecoder.cs

125
src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTable.cs

@ -16,13 +16,9 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
internal struct HuffmanTable : IDisposable internal struct HuffmanTable : IDisposable
{ {
private Buffer<short> lookahead; private Buffer<short> lookahead;
private Buffer<short> huffcode;
private Buffer<short> huffsize;
private Buffer<short> valOffset; private Buffer<short> valOffset;
private Buffer<long> maxcode; private Buffer<long> maxcode;
private Buffer<byte> huffval; private Buffer<byte> huffval;
private Buffer<byte> bits;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HuffmanTable"/> struct. /// Initializes a new instance of the <see cref="HuffmanTable"/> struct.
@ -32,119 +28,113 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
public HuffmanTable(byte[] lengths, byte[] values) public HuffmanTable(byte[] lengths, byte[] values)
{ {
this.lookahead = Buffer<short>.CreateClean(256); this.lookahead = Buffer<short>.CreateClean(256);
this.huffcode = Buffer<short>.CreateClean(257);
this.huffsize = Buffer<short>.CreateClean(257);
this.valOffset = Buffer<short>.CreateClean(18); this.valOffset = Buffer<short>.CreateClean(18);
this.maxcode = Buffer<long>.CreateClean(18); this.maxcode = Buffer<long>.CreateClean(18);
using (var huffsize = Buffer<short>.CreateClean(257))
using (var huffcode = Buffer<short>.CreateClean(257))
{
GenerateSizeTable(lengths, huffsize);
GenerateCodeTable(huffsize, huffcode);
GenerateDecoderTables(lengths, huffcode, this.valOffset, this.maxcode);
GenerateLookaheadTables(lengths, values, this.lookahead);
}
this.huffval = Buffer<byte>.CreateClean(values.Length); this.huffval = Buffer<byte>.CreateClean(values.Length);
Buffer.BlockCopy(values, 0, this.huffval.Array, 0, values.Length); Buffer.BlockCopy(values, 0, this.huffval.Array, 0, values.Length);
this.bits = Buffer<byte>.CreateClean(lengths.Length); this.MaxCode = this.maxcode.Array;
Buffer.BlockCopy(lengths, 0, this.bits.Array, 0, lengths.Length); this.ValOffset = this.valOffset.Array;
this.HuffVal = this.huffval.Array;
this.GenerateSizeTable(); this.Lookahead = this.lookahead.Array;
this.GenerateCodeTable();
this.GenerateDecoderTables();
this.GenerateLookaheadTables();
} }
/// <summary> /// <summary>
/// Gets the Huffman value code at the given index /// Gets the max code array
/// </summary> /// </summary>
/// <param name="i">The index</param> public long[] MaxCode
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public short GetHuffVal(int i)
{ {
return this.huffval[i]; [MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
} }
/// <summary> /// <summary>
/// Gets the max code at the given index /// Gets the value offset array
/// </summary> /// </summary>
/// <param name="i">The index</param> public short[] ValOffset
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public long GetMaxCode(int i)
{ {
return this.maxcode[i]; [MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
} }
/// <summary> /// <summary>
/// Gets the index to the locatation of the huffman value /// Gets the huffman value array
/// </summary> /// </summary>
/// <param name="i">The index</param> public byte[] HuffVal
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetValOffset(int i)
{ {
return this.valOffset[i]; [MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
} }
/// <summary> /// <summary>
/// Gets the look ahead table balue /// Gets the lookahead array
/// </summary> /// </summary>
/// <param name="i">The index</param> public short[] Lookahead
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetLookAhead(int i)
{ {
return this.lookahead[i]; [MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
} }
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
{ {
this.lookahead?.Dispose(); this.lookahead?.Dispose();
this.huffcode?.Dispose();
this.huffsize?.Dispose();
this.valOffset?.Dispose(); this.valOffset?.Dispose();
this.maxcode?.Dispose(); this.maxcode?.Dispose();
this.huffval?.Dispose(); this.huffval?.Dispose();
this.bits?.Dispose();
this.lookahead = null; this.lookahead = null;
this.huffcode = null;
this.huffsize = null;
this.valOffset = null; this.valOffset = null;
this.maxcode = null; this.maxcode = null;
this.huffval = null; this.huffval = null;
this.bits = null;
} }
/// <summary> /// <summary>
/// Figure C.1: make table of Huffman code length for each symbol /// Figure C.1: make table of Huffman code length for each symbol
/// </summary> /// </summary>
private void GenerateSizeTable() /// <param name="lengths">The code lengths</param>
/// <param name="huffsize">The huffman size span</param>
private static void GenerateSizeTable(byte[] lengths, Span<short> huffsize)
{ {
short index = 0; short index = 0;
for (short l = 1; l <= 16; l++) for (short l = 1; l <= 16; l++)
{ {
byte i = this.bits[l]; byte i = lengths[l];
for (short j = 0; j < i; j++) for (short j = 0; j < i; j++)
{ {
this.huffsize[index] = l; huffsize[index] = l;
index++; index++;
} }
} }
this.huffsize[index] = 0; huffsize[index] = 0;
} }
/// <summary> /// <summary>
/// Figure C.2: generate the codes themselves /// Figure C.2: generate the codes themselves
/// </summary> /// </summary>
private void GenerateCodeTable() /// <param name="huffsize">The huffman size span</param>
/// <param name="huffcode">The huffman code span</param>
private static void GenerateCodeTable(Span<short> huffsize, Span<short> huffcode)
{ {
short k = 0; short k = 0;
short si = this.huffsize[0]; short si = huffsize[0];
short code = 0; short code = 0;
for (short i = 0; i < this.huffsize.Length; i++) for (short i = 0; i < huffsize.Length; i++)
{ {
while (this.huffsize[k] == si) while (huffsize[k] == si)
{ {
this.huffcode[k] = code; huffcode[k] = code;
code++; code++;
k++; k++;
} }
@ -157,33 +147,40 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
/// <summary> /// <summary>
/// Figure F.15: generate decoding tables for bit-sequential decoding /// Figure F.15: generate decoding tables for bit-sequential decoding
/// </summary> /// </summary>
private void GenerateDecoderTables() /// <param name="lengths">The code lengths</param>
/// <param name="huffcode">The huffman code span</param>
/// <param name="valOffset">The value offset span</param>
/// <param name="maxcode">The max code span</param>
private static void GenerateDecoderTables(byte[] lengths, Span<short> huffcode, Span<short> valOffset, Span<long> maxcode)
{ {
short bitcount = 0; short bitcount = 0;
for (int i = 1; i <= 16; i++) for (int i = 1; i <= 16; i++)
{ {
if (this.bits[i] != 0) if (lengths[i] != 0)
{ {
// valoffset[l] = huffval[] index of 1st symbol of code length i, // valoffset[l] = huffval[] index of 1st symbol of code length i,
// minus the minimum code of length i // minus the minimum code of length i
this.valOffset[i] = (short)(bitcount - this.huffcode[bitcount]); valOffset[i] = (short)(bitcount - huffcode[bitcount]);
bitcount += this.bits[i]; bitcount += lengths[i];
this.maxcode[i] = this.huffcode[bitcount - 1]; // maximum code of length i maxcode[i] = huffcode[bitcount - 1]; // maximum code of length i
} }
else else
{ {
this.maxcode[i] = -1; // -1 if no codes of this length maxcode[i] = -1; // -1 if no codes of this length
} }
} }
this.valOffset[17] = 0; valOffset[17] = 0;
this.maxcode[17] = 0xFFFFFL; maxcode[17] = 0xFFFFFL;
} }
/// <summary> /// <summary>
/// Generates lookup tables to speed up decoding /// Generates lookup tables to speed up decoding
/// </summary> /// </summary>
private void GenerateLookaheadTables() /// <param name="lengths">The code lengths</param>
/// <param name="huffval">The huffman value array</param>
/// <param name="lookahead">The lookahead span</param>
private static void GenerateLookaheadTables(byte[] lengths, byte[] huffval, Span<short> lookahead)
{ {
int x = 0, code = 0; int x = 0, code = 0;
@ -191,7 +188,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
{ {
code <<= 1; code <<= 1;
for (int j = 0; j < this.bits[i + 1]; j++) for (int j = 0; j < lengths[i + 1]; j++)
{ {
// The codeLength is 1+i, so shift code by 8-(1+i) to // The codeLength is 1+i, so shift code by 8-(1+i) to
// calculate the high bits for every 8-bit sequence // calculate the high bits for every 8-bit sequence
@ -199,11 +196,11 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
// The high 8 bits of lutValue are the encoded value. // The high 8 bits of lutValue are the encoded value.
// The low 8 bits are 1 plus the codeLength. // The low 8 bits are 1 plus the codeLength.
byte base2 = (byte)(code << (7 - i)); byte base2 = (byte)(code << (7 - i));
short lutValue = (short)((short)(this.huffval[x] << 8) | (short)(2 + i)); short lutValue = (short)((short)(huffval[x] << 8) | (short)(2 + i));
for (int k = 0; k < 1 << (7 - i); k++) for (int k = 0; k < 1 << (7 - i); k++)
{ {
this.lookahead[base2 | k] = lutValue; lookahead[base2 | k] = lutValue;
} }
code++; code++;

8
src/ImageSharp/Formats/Jpeg/Port/Components/ScanDecoder.cs

@ -635,7 +635,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
// } // }
// this.accumulator = (this.accumulator << 8) | this.bitsData; // this.accumulator = (this.accumulator << 8) | this.bitsData;
// int lutIndex = (this.accumulator >> (this.bitsUnRead - 8)) & 0xFF; // int lutIndex = (this.accumulator >> (this.bitsUnRead - 8)) & 0xFF;
// int v = tree.GetLookAhead(lutIndex); // int v = tree.Lookahead[lutIndex];
// if (v != 0) // if (v != 0)
// { // {
// int nb = (v & 0xFF) - 1; // int nb = (v & 0xFF) - 1;
@ -657,7 +657,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
// "DECODE", section F.2.2.3, figure F.16, page 109 of T.81 // "DECODE", section F.2.2.3, figure F.16, page 109 of T.81
int i = 1; int i = 1;
while (code > tree.GetMaxCode(i)) while (code > tree.MaxCode[i])
{ {
code <<= 1; code <<= 1;
code |= (short)this.ReadBit(stream); code |= (short)this.ReadBit(stream);
@ -670,8 +670,8 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
i++; i++;
} }
int j = tree.GetValOffset(i); int j = tree.ValOffset[i];
return tree.GetHuffVal((j + code) & 0xFF); return tree.HuffVal[(j + code) & 0xFF];
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

Loading…
Cancel
Save