From 3728b821ddf25f3738bc240b875d09398c7913c2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 20 Jun 2017 01:19:47 +1000 Subject: [PATCH] =?UTF-8?q?(=E2=95=AF=C2=B0=E2=96=A1=C2=B0=EF=BC=89?= =?UTF-8?q?=E2=95=AF=EF=B8=B5=20=E2=94=BB=E2=94=81=E2=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Jpeg/Port/Components/HuffmanTables.cs | 30 ++++++- .../Formats/Jpeg/Port/JpegDecoderCore.cs | 83 +++++++++++++++---- 2 files changed, 98 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTables.cs b/src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTables.cs index 5c4ffce248..5fcc2007b9 100644 --- a/src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Port/Components/HuffmanTables.cs @@ -1,5 +1,7 @@ namespace ImageSharp.Formats.Jpeg.Port.Components { + using System.Collections.Generic; + using ImageSharp.Memory; /// @@ -10,6 +12,32 @@ internal class HuffmanTables /// /// Gets or sets the quantization tables. /// - public Fast2DArray Tables { get; set; } = new Fast2DArray(256, 2); + public Fast2DArray Tables { get; set; } = new Fast2DArray(256, 2); + } + + internal struct HuffmanBranch + { + public HuffmanBranch(short value) + : this(value, new List()) + { + } + + public HuffmanBranch(List children) + : this(0, children) + { + } + + private HuffmanBranch(short value, List children) + { + this.Index = 0; + this.Value = value; + this.Children = children; + } + + public int Index; + + public short Value; + + public List Children; } } diff --git a/src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs index 1b2b8b99f9..db25ba8453 100644 --- a/src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/Port/JpegDecoderCore.cs @@ -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(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(256)) + using (var values = new Buffer(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 tableSpan = tables.Tables.GetRowSpan(index); + var code = new Queue(); + code.Enqueue(new HuffmanBranch(new List())); + HuffmanBranch p = code.Peek(); + p.Children = new List(); + 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(); + } + + p.Index++; + code.Enqueue(p); + while (code.Count <= i) + { + q = new HuffmanBranch(new List()); + 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()); + code.Enqueue(q); + p.Children.Add(new HuffmanBranch(q.Children)); + p = q; + } + } + + Span tableSpan = tables.Tables.GetRowSpan(index); + + List result = code.Peek().Children; + for (int i = 0; i < result.Count; i++) + { + tableSpan[i] = result[i]; + } + } + catch (Exception e) + { + throw; + } } ///