-
-
Notifications
You must be signed in to change notification settings - Fork 854
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
namespace ImageSharp.Formats.Jpeg.Port.Components | ||
{ | ||
using System.Collections.Generic; | ||
|
||
using ImageSharp.Memory; | ||
|
||
/// <summary> | ||
|
@@ -10,6 +12,32 @@ internal class HuffmanTables | |
/// <summary> | ||
/// Gets or sets the quantization tables. | ||
/// </summary> | ||
public Fast2DArray<short> Tables { get; set; } = new Fast2DArray<short>(256, 2); | ||
public Fast2DArray<HuffmanBranch> Tables { get; set; } = new Fast2DArray<HuffmanBranch>(256, 2); | ||
} | ||
|
||
internal struct HuffmanBranch | ||
{ | ||
public HuffmanBranch(short value) | ||
: this(value, new List<HuffmanBranch>()) | ||
{ | ||
} | ||
|
||
public HuffmanBranch(List<HuffmanBranch> children) | ||
: this(0, children) | ||
{ | ||
} | ||
|
||
private HuffmanBranch(short value, List<HuffmanBranch> children) | ||
{ | ||
this.Index = 0; | ||
this.Value = value; | ||
this.Children = children; | ||
} | ||
|
||
public int Index; | ||
|
||
public short Value; | ||
|
||
public List<HuffmanBranch> Children; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
JimBobSquarePants
Author
Member
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,8 +6,9 @@ | |
namespace ImageSharp.Formats.Jpeg.Port | ||
{ | ||
using System; | ||
using System.Buffers; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
|
||
using ImageSharp.Formats.Jpeg.Port.Components; | ||
using ImageSharp.Memory; | ||
|
@@ -346,9 +347,9 @@ private void ProcessDefineHuffmanTablesMarker(int remaining) | |
|
||
using (var huffmanData = new Buffer<byte>(remaining)) | ||
{ | ||
this.InputStream.Read(huffmanData.Array, 1, remaining); | ||
this.InputStream.Skip(1); | ||
this.InputStream.Read(huffmanData.Array, 0, remaining); | ||
|
||
int o = 0; | ||
for (int i = 0; i < remaining;) | ||
{ | ||
byte huffmanTableSpec = huffmanData[i]; | ||
|
@@ -357,41 +358,95 @@ private void ProcessDefineHuffmanTablesMarker(int remaining) | |
|
||
for (int j = 0; j < 16; j++) | ||
{ | ||
codeLengthSum += codeLengths[j] = huffmanData[o++]; | ||
codeLengthSum += codeLengths[j] = huffmanData[j]; | ||
} | ||
|
||
// TODO: Pooling? | ||
short[] huffmanValues = new short[codeLengthSum]; | ||
using (var values = new Buffer<byte>(256)) | ||
using (var values = new Buffer<byte>(codeLengthSum)) | ||
{ | ||
this.InputStream.Read(values.Array, 0, codeLengthSum); | ||
|
||
for (int j = 0; j < codeLengthSum; j++) | ||
{ | ||
huffmanValues[j] = values[o++]; | ||
huffmanValues[j] = values[j]; | ||
} | ||
} | ||
|
||
i += 17 + codeLengthSum; | ||
i += 17 + codeLengthSum; | ||
|
||
this.BuildHuffmanTable( | ||
huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables, | ||
huffmanTableSpec & 15, | ||
codeLengths, | ||
huffmanValues); | ||
this.BuildHuffmanTable( | ||
huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables, | ||
huffmanTableSpec & 15, | ||
codeLengths, | ||
huffmanValues); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void BuildHuffmanTable(HuffmanTables tables, int index, byte[] codeLengths, short[] values) | ||
{ | ||
// (╯°□°)╯︵ ┻━┻ Everything up to here is going well. I can't match the JavaScript now though. | ||
int length = 16; | ||
while (length > 0 && codeLengths[length - 1] == 0) | ||
{ | ||
length--; | ||
} | ||
|
||
Span<short> tableSpan = tables.Tables.GetRowSpan(index); | ||
var code = new Queue<HuffmanBranch>(); | ||
code.Enqueue(new HuffmanBranch(new List<HuffmanBranch>())); | ||
HuffmanBranch p = code.Peek(); | ||
p.Children = new List<HuffmanBranch>(); | ||
HuffmanBranch q; | ||
int k = 0; | ||
try | ||
{ | ||
for (int i = 0; i < length; i++) | ||
{ | ||
for (int j = 0; j < codeLengths[i]; j++) | ||
{ | ||
p = code.Dequeue(); | ||
p.Children.Add(new HuffmanBranch(values[k])); | ||
while (p.Index > 0) | ||
{ | ||
p = code.Dequeue(); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
|
||
p.Index++; | ||
This comment has been minimized.
Sorry, something went wrong.
tocsoft
Member
|
||
code.Enqueue(p); | ||
while (code.Count <= i) | ||
{ | ||
q = new HuffmanBranch(new List<HuffmanBranch>()); | ||
code.Enqueue(q); | ||
p.Children.Add(new HuffmanBranch(q.Children)); | ||
p = q; | ||
} | ||
|
||
k++; | ||
} | ||
|
||
if (i + 1 < length) | ||
{ | ||
// p here points to last code | ||
q = new HuffmanBranch(new List<HuffmanBranch>()); | ||
code.Enqueue(q); | ||
p.Children.Add(new HuffmanBranch(q.Children)); | ||
p = q; | ||
} | ||
} | ||
|
||
Span<HuffmanBranch> tableSpan = tables.Tables.GetRowSpan(index); | ||
|
||
List<HuffmanBranch> result = code.Peek().Children; | ||
This comment has been minimized.
Sorry, something went wrong.
tocsoft
Member
|
||
for (int i = 0; i < result.Count; i++) | ||
{ | ||
tableSpan[i] = result[i]; | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
throw; | ||
} | ||
} | ||
|
||
/// <summary> | ||
|
I was reading the js code and interesting fact is that there seems to only ever be 2 children of any node, and in where they are decoded later it ends up navigating the tree using a series of bools to switching between the 2 trees looking for the first node with a value set.