Browse Source

Better Huffman decoding

pull/298/head
James Jackson-South 9 years ago
parent
commit
0f6024247b
  1. 1
      src/ImageSharp/Formats/Jpeg/Port/Components/Component.cs
  2. 1
      src/ImageSharp/Formats/Jpeg/Port/Components/FrameComponent.cs
  3. 54
      src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanBranch.cs
  4. 59
      src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTable.cs
  5. 12
      src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTables.cs
  6. 4
      src/ImageSharp/Formats/Jpeg/Port/Components/ScanDecoder.cs
  7. 6
      src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs

1
src/ImageSharp/Formats/Jpeg/Port/Components/Component.cs

@ -43,6 +43,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
public void Dispose() public void Dispose()
{ {
this.Output?.Dispose(); this.Output?.Dispose();
this.Output = null;
} }
} }
} }

1
src/ImageSharp/Formats/Jpeg/Port/Components/FrameComponent.cs

@ -68,6 +68,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
public void Dispose() public void Dispose()
{ {
this.BlockData?.Dispose(); this.BlockData?.Dispose();
this.BlockData = null;
} }
} }
} }

54
src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanBranch.cs

@ -1,54 +0,0 @@
// <copyright file="HuffmanBranch.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats.Jpeg.Port.Components
{
using System.Runtime.CompilerServices;
/// <summary>
/// Represents a branch in the huffman tree
/// </summary>
internal struct HuffmanBranch
{
/// <summary>
/// The index
/// </summary>
public int Index;
/// <summary>
/// The value
/// </summary>
public short Value;
/// <summary>
/// The children.
/// </summary>
public HuffmanBranch[] Children;
/// <summary>
/// Initializes a new instance of the <see cref="HuffmanBranch"/> struct.
/// </summary>
/// <param name="value">The value</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HuffmanBranch(short value)
{
this.Index = 0;
this.Value = value;
this.Children = new HuffmanBranch[2];
}
/// <summary>
/// Initializes a new instance of the <see cref="HuffmanBranch"/> struct.
/// </summary>
/// <param name="children">The branch children</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HuffmanBranch(HuffmanBranch[] children)
{
this.Index = 0;
this.Value = -1;
this.Children = children;
}
}
}

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

@ -1,32 +1,45 @@
namespace ImageSharp.Formats.Jpeg.Port.Components // <copyright file="HuffmanTable.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats.Jpeg.Port.Components
{ {
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using ImageSharp.Memory;
/// <summary> /// <summary>
/// Represents a HUffman Table /// Represents a Huffman Table
/// </summary> /// </summary>
internal sealed class HuffmanTable internal struct HuffmanTable : IDisposable
{ {
private short[] huffcode = new short[257]; private Buffer<short> huffcode;
private short[] huffsize = new short[257]; private Buffer<short> huffsize;
private short[] valOffset = new short[18]; private Buffer<short> valOffset;
private long[] maxcode = new long[18]; private Buffer<long> maxcode;
private byte[] huffval; private Buffer<byte> huffval;
private byte[] bits; private Buffer<byte> bits;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HuffmanTable"/> class. /// Initializes a new instance of the <see cref="HuffmanTable"/> struct.
/// </summary> /// </summary>
/// <param name="lengths">The code lengths</param> /// <param name="lengths">The code lengths</param>
/// <param name="values">The huffman values</param> /// <param name="values">The huffman values</param>
public HuffmanTable(byte[] lengths, byte[] values) public HuffmanTable(byte[] lengths, byte[] values)
{ {
this.huffval = new byte[values.Length]; this.huffcode = Buffer<short>.CreateClean(257);
Buffer.BlockCopy(values, 0, this.huffval, 0, values.Length); this.huffsize = Buffer<short>.CreateClean(257);
this.bits = new byte[lengths.Length]; this.valOffset = Buffer<short>.CreateClean(18);
Buffer.BlockCopy(lengths, 0, this.bits, 0, lengths.Length); this.maxcode = Buffer<long>.CreateClean(18);
this.huffval = Buffer<byte>.CreateClean(values.Length);
Buffer.BlockCopy(values, 0, this.huffval.Array, 0, values.Length);
this.bits = Buffer<byte>.CreateClean(lengths.Length);
Buffer.BlockCopy(lengths, 0, this.bits.Array, 0, lengths.Length);
this.GenerateSizeTable(); this.GenerateSizeTable();
this.GenerateCodeTable(); this.GenerateCodeTable();
@ -66,6 +79,24 @@
return this.valOffset[i]; return this.valOffset[i];
} }
/// <inheritdoc/>
public void Dispose()
{
this.huffcode?.Dispose();
this.huffsize?.Dispose();
this.valOffset?.Dispose();
this.maxcode?.Dispose();
this.huffval?.Dispose();
this.bits?.Dispose();
this.huffcode = null;
this.huffsize = null;
this.valOffset = null;
this.maxcode = 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>

12
src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTables.cs

@ -5,13 +5,14 @@
namespace ImageSharp.Formats.Jpeg.Port.Components namespace ImageSharp.Formats.Jpeg.Port.Components
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
/// <summary> /// <summary>
/// Defines a pair of huffman tables /// Defines a pair of huffman tables
/// </summary> /// </summary>
internal class HuffmanTables internal sealed class HuffmanTables : IDisposable
{ {
private readonly HuffmanTable[] tables = new HuffmanTable[4]; private readonly HuffmanTable[] tables = new HuffmanTable[4];
@ -34,5 +35,14 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
this.tables[index] = value; this.tables[index] = value;
} }
} }
/// <inheritdoc/>
public void Dispose()
{
for (int i = 0; i < this.tables.Length; i++)
{
this.tables[i].Dispose();
}
}
} }
} }

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

@ -734,7 +734,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
return; return;
} }
var componentBlockDataSpan = component.BlockData.Span; Span<short> componentBlockDataSpan = component.BlockData.Span;
int k = this.specStart; int k = this.specStart;
int e = this.specEnd; int e = this.specEnd;
while (k <= e) while (k <= e)
@ -773,7 +773,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
int k = this.specStart; int k = this.specStart;
int e = this.specEnd; int e = this.specEnd;
int r = 0; int r = 0;
var componentBlockDataSpan = component.BlockData.Span; Span<short> componentBlockDataSpan = component.BlockData.Span;
while (k <= e) while (k <= e)
{ {
byte z = QuantizationTables.DctZigZag[k]; byte z = QuantizationTables.DctZigZag[k];

6
src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs

@ -160,12 +160,16 @@ namespace ImageSharp.Formats.Jpeg.Port
this.frame?.Dispose(); this.frame?.Dispose();
this.components?.Dispose(); this.components?.Dispose();
this.quantizationTables?.Dispose(); this.quantizationTables?.Dispose();
this.dcHuffmanTables?.Dispose();
this.acHuffmanTables?.Dispose();
this.pixelArea.Dispose(); this.pixelArea.Dispose();
// Set large fields to null. // Set large fields to null.
this.frame = null; this.frame = null;
this.components = null; this.components = null;
this.quantizationTables = null; this.quantizationTables = null;
this.dcHuffmanTables = null;
this.acHuffmanTables = null;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -696,7 +700,7 @@ namespace ImageSharp.Formats.Jpeg.Port
this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum); this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum);
i += 17 + codeLengthSum; i += 17 + codeLengthSum;
Debug.WriteLine(huffmanTableSpec >> 4 == 0 ? "this.dcHuffmanTables" : "this.acHuffmanTables");
this.BuildHuffmanTable( this.BuildHuffmanTable(
huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables, huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables,
huffmanTableSpec & 15, huffmanTableSpec & 15,

Loading…
Cancel
Save