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()
{
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()
{
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.Runtime.CompilerServices;
using ImageSharp.Memory;
/// <summary>
/// Represents a HUffman Table
/// Represents a Huffman Table
/// </summary>
internal sealed class HuffmanTable
internal struct HuffmanTable : IDisposable
{
private short[] huffcode = new short[257];
private short[] huffsize = new short[257];
private short[] valOffset = new short[18];
private long[] maxcode = new long[18];
private Buffer<short> huffcode;
private Buffer<short> huffsize;
private Buffer<short> valOffset;
private Buffer<long> maxcode;
private byte[] huffval;
private byte[] bits;
private Buffer<byte> huffval;
private Buffer<byte> bits;
/// <summary>
/// Initializes a new instance of the <see cref="HuffmanTable"/> class.
/// Initializes a new instance of the <see cref="HuffmanTable"/> struct.
/// </summary>
/// <param name="lengths">The code lengths</param>
/// <param name="values">The huffman values</param>
public HuffmanTable(byte[] lengths, byte[] values)
{
this.huffval = new byte[values.Length];
Buffer.BlockCopy(values, 0, this.huffval, 0, values.Length);
this.bits = new byte[lengths.Length];
Buffer.BlockCopy(lengths, 0, this.bits, 0, lengths.Length);
this.huffcode = Buffer<short>.CreateClean(257);
this.huffsize = Buffer<short>.CreateClean(257);
this.valOffset = Buffer<short>.CreateClean(18);
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.GenerateCodeTable();
@ -66,6 +79,24 @@
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>
/// Figure C.1: make table of Huffman code length for each symbol
/// </summary>

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

@ -5,13 +5,14 @@
namespace ImageSharp.Formats.Jpeg.Port.Components
{
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
/// <summary>
/// Defines a pair of huffman tables
/// </summary>
internal class HuffmanTables
internal sealed class HuffmanTables : IDisposable
{
private readonly HuffmanTable[] tables = new HuffmanTable[4];
@ -34,5 +35,14 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
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;
}
var componentBlockDataSpan = component.BlockData.Span;
Span<short> componentBlockDataSpan = component.BlockData.Span;
int k = this.specStart;
int e = this.specEnd;
while (k <= e)
@ -773,7 +773,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components
int k = this.specStart;
int e = this.specEnd;
int r = 0;
var componentBlockDataSpan = component.BlockData.Span;
Span<short> componentBlockDataSpan = component.BlockData.Span;
while (k <= e)
{
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.components?.Dispose();
this.quantizationTables?.Dispose();
this.dcHuffmanTables?.Dispose();
this.acHuffmanTables?.Dispose();
this.pixelArea.Dispose();
// Set large fields to null.
this.frame = null;
this.components = null;
this.quantizationTables = null;
this.dcHuffmanTables = null;
this.acHuffmanTables = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -696,7 +700,7 @@ namespace ImageSharp.Formats.Jpeg.Port
this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum);
i += 17 + codeLengthSum;
Debug.WriteLine(huffmanTableSpec >> 4 == 0 ? "this.dcHuffmanTables" : "this.acHuffmanTables");
this.BuildHuffmanTable(
huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables,
huffmanTableSpec & 15,

Loading…
Cancel
Save