diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs
index 3d2856b0e..bc7ad7a38 100644
--- a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs
+++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs
@@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-//
using System;
using System.Collections.Generic;
using System.Text;
@@ -18,106 +17,409 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
///
public class DeflaterHuffman
{
- private const int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
- private const int LITERAL_NUM = 286;
+ private const int BufferSize = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
+
+ // The number of literal codes.
+ private const int LiteralNumber = 286;
// Number of distance codes
- private const int DIST_NUM = 30;
+ private const int DistanceNumber = 30;
// Number of codes used to transfer bit lengths
- private const int BITLEN_NUM = 19;
+ private const int BitLengthNumber = 19;
// repeat previous bit length 3-6 times (2 bits of repeat count)
- private const int REP_3_6 = 16;
+ private const int Repeat3To6 = 16;
// repeat a zero length 3-10 times (3 bits of repeat count)
- private const int REP_3_10 = 17;
+ private const int Repeat3To10 = 17;
// repeat a zero length 11-138 times (7 bits of repeat count)
- private const int REP_11_138 = 18;
+ private const int Repeat11To138 = 18;
- private const int EOF_SYMBOL = 256;
+ private const int EofSymbol = 256;
// The lengths of the bit length codes are sent in order of decreasing
// probability, to avoid transmitting the lengths for unused bit length codes.
- private static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
-
- private static readonly byte[] bit4Reverse = {
- 0,
- 8,
- 4,
- 12,
- 2,
- 10,
- 6,
- 14,
- 1,
- 9,
- 5,
- 13,
- 3,
- 11,
- 7,
- 15
- };
+ private static readonly int[] BitLengthOrder = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+ private static readonly byte[] Bit4Reverse = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
private static short[] staticLCodes;
private static byte[] staticLLength;
private static short[] staticDCodes;
private static byte[] staticDLength;
- private class Tree
+ private Tree literalTree;
+ private Tree distTree;
+ private Tree blTree;
+
+ // Buffer for distances
+ private short[] distanceBuffer;
+
+ private byte[] literalBuffer;
+ private int lastLiteral;
+ private int extraBits;
+
+ static DeflaterHuffman()
+ {
+ // See RFC 1951 3.2.6
+ // Literal codes
+ staticLCodes = new short[LiteralNumber];
+ staticLLength = new byte[LiteralNumber];
+
+ int i = 0;
+ while (i < 144)
+ {
+ staticLCodes[i] = BitReverse((0x030 + i) << 8);
+ staticLLength[i++] = 8;
+ }
+
+ while (i < 256)
+ {
+ staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
+ staticLLength[i++] = 9;
+ }
+
+ while (i < 280)
+ {
+ staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
+ staticLLength[i++] = 7;
+ }
+
+ while (i < LiteralNumber)
+ {
+ staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
+ staticLLength[i++] = 8;
+ }
+
+ // Distance codes
+ staticDCodes = new short[DistanceNumber];
+ staticDLength = new byte[DistanceNumber];
+ for (i = 0; i < DistanceNumber; i++)
+ {
+ staticDCodes[i] = BitReverse(i << 11);
+ staticDLength[i] = 5;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Pending buffer to use
+ public DeflaterHuffman(DeflaterPendingBuffer pending)
{
- #region Instance Fields
+ this.Pending = pending;
- public short[] freqs;
+ this.literalTree = new Tree(this, LiteralNumber, 257, 15);
+ this.distTree = new Tree(this, DistanceNumber, 1, 15);
+ this.blTree = new Tree(this, BitLengthNumber, 4, 7);
- public byte[] length;
+ this.distanceBuffer = new short[BufferSize];
+ this.literalBuffer = new byte[BufferSize];
+ }
- public int minNumCodes;
+ ///
+ /// Gets the pending buffer to use.
+ ///
+ public DeflaterPendingBuffer Pending { get; }
- public int numCodes;
+ ///
+ /// Reset internal state
+ ///
+ public void Reset()
+ {
+ this.lastLiteral = 0;
+ this.extraBits = 0;
+ this.literalTree.Reset();
+ this.distTree.Reset();
+ this.blTree.Reset();
+ }
- private short[] codes;
- private readonly int[] bl_counts;
- private readonly int maxLength;
- private DeflaterHuffman dh;
+ ///
+ /// Write all trees to pending buffer
+ ///
+ /// The number/rank of treecodes to send.
+ public void SendAllTrees(int blTreeCodes)
+ {
+ this.blTree.BuildCodes();
+ this.literalTree.BuildCodes();
+ this.distTree.BuildCodes();
+ this.Pending.WriteBits(this.literalTree.NumCodes - 257, 5);
+ this.Pending.WriteBits(this.distTree.NumCodes - 1, 5);
+ this.Pending.WriteBits(blTreeCodes - 4, 4);
+ for (int rank = 0; rank < blTreeCodes; rank++)
+ {
+ this.Pending.WriteBits(this.blTree.Length[BitLengthOrder[rank]], 3);
+ }
+
+ this.literalTree.WriteTree(this.blTree);
+ this.distTree.WriteTree(this.blTree);
+ }
+
+ ///
+ /// Compress current buffer writing data to pending buffer
+ ///
+ public void CompressBlock()
+ {
+ for (int i = 0; i < this.lastLiteral; i++)
+ {
+ int litlen = this.literalBuffer[i] & 0xff;
+ int dist = this.distanceBuffer[i];
+ if (dist-- != 0)
+ {
+ int lc = Lcode(litlen);
+ this.literalTree.WriteSymbol(lc);
+
+ int bits = (lc - 261) / 4;
+ if (bits > 0 && bits <= 5)
+ {
+ this.Pending.WriteBits(litlen & ((1 << bits) - 1), bits);
+ }
+
+ int dc = Dcode(dist);
+ this.distTree.WriteSymbol(dc);
+
+ bits = (dc / 2) - 1;
+ if (bits > 0)
+ {
+ this.Pending.WriteBits(dist & ((1 << bits) - 1), bits);
+ }
+ }
+ else
+ {
+ this.literalTree.WriteSymbol(litlen);
+ }
+ }
+
+ this.literalTree.WriteSymbol(EofSymbol);
+ }
+
+ ///
+ /// Flush block to output with no compression
+ ///
+ /// Data to write
+ /// Index of first byte to write
+ /// Count of bytes to write
+ /// True if this is the last block
+ public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ {
+ this.Pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
+ this.Pending.AlignToByte();
+ this.Pending.WriteShort(storedLength);
+ this.Pending.WriteShort(~storedLength);
+ this.Pending.WriteBlock(stored, storedOffset, storedLength);
+ this.Reset();
+ }
+
+ ///
+ /// Flush block to output with compression
+ ///
+ /// Data to flush
+ /// Index of first byte to flush
+ /// Count of bytes to flush
+ /// True if this is the last block
+ public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ {
+ this.literalTree.Freqs[EofSymbol]++;
+
+ // Build trees
+ this.literalTree.BuildTree();
+ this.distTree.BuildTree();
+
+ // Calculate bitlen frequency
+ this.literalTree.CalcBLFreq(this.blTree);
+ this.distTree.CalcBLFreq(this.blTree);
+
+ // Build bitlen tree
+ this.blTree.BuildTree();
+
+ int blTreeCodes = 4;
+ for (int i = 18; i > blTreeCodes; i--)
+ {
+ if (this.blTree.Length[BitLengthOrder[i]] > 0)
+ {
+ blTreeCodes = i + 1;
+ }
+ }
+
+ int opt_len = 14 + (blTreeCodes * 3) + this.blTree.GetEncodedLength() +
+ this.literalTree.GetEncodedLength() + this.distTree.GetEncodedLength() +
+ this.extraBits;
+
+ int static_len = this.extraBits;
+ for (int i = 0; i < LiteralNumber; i++)
+ {
+ static_len += this.literalTree.Freqs[i] * staticLLength[i];
+ }
+
+ for (int i = 0; i < DistanceNumber; i++)
+ {
+ static_len += this.distTree.Freqs[i] * staticDLength[i];
+ }
+
+ if (opt_len >= static_len)
+ {
+ // Force static trees
+ opt_len = static_len;
+ }
+
+ if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3)
+ {
+ // Store Block
+ this.FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
+ }
+ else if (opt_len == static_len)
+ {
+ // Encode with static tree
+ this.Pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3);
+ this.literalTree.SetStaticCodes(staticLCodes, staticLLength);
+ this.distTree.SetStaticCodes(staticDCodes, staticDLength);
+ this.CompressBlock();
+ this.Reset();
+ }
+ else
+ {
+ // Encode with dynamic tree
+ this.Pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3);
+ this.SendAllTrees(blTreeCodes);
+ this.CompressBlock();
+ this.Reset();
+ }
+ }
+
+ ///
+ /// Get value indicating if internal buffer is full
+ ///
+ /// true if buffer is full
+ public bool IsFull()
+ {
+ return this.lastLiteral >= BufferSize;
+ }
+
+ ///
+ /// Add literal to buffer
+ ///
+ /// Literal value to add to buffer.
+ /// Value indicating internal buffer is full
+ public bool TallyLit(int literal)
+ {
+ this.distanceBuffer[this.lastLiteral] = 0;
+ this.literalBuffer[this.lastLiteral++] = (byte)literal;
+ this.literalTree.Freqs[literal]++;
+ return this.IsFull();
+ }
+
+ ///
+ /// Add distance code and length to literal and distance trees
+ ///
+ /// Distance code
+ /// Length
+ /// Value indicating if internal buffer is full
+ public bool TallyDist(int distance, int length)
+ {
+ this.distanceBuffer[this.lastLiteral] = (short)distance;
+ this.literalBuffer[this.lastLiteral++] = (byte)(length - 3);
+
+ int lc = Lcode(length - 3);
+ this.literalTree.Freqs[lc]++;
+ if (lc >= 265 && lc < 285)
+ {
+ this.extraBits += (lc - 261) / 4;
+ }
+
+ int dc = Dcode(distance - 1);
+ this.distTree.Freqs[dc]++;
+ if (dc >= 4)
+ {
+ this.extraBits += (dc / 2) - 1;
+ }
+
+ return this.IsFull();
+ }
+
+ ///
+ /// Reverse the bits of a 16 bit value.
+ ///
+ /// Value to reverse bits
+ /// Value with bits reversed
+ public static short BitReverse(int toReverse)
+ {
+ return (short)(Bit4Reverse[toReverse & 0xF] << 12 |
+ Bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
+ Bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
+ Bit4Reverse[toReverse >> 12]);
+ }
+
+ private static int Lcode(int length)
+ {
+ if (length == 255)
+ {
+ return 285;
+ }
+
+ int code = 257;
+ while (length >= 8)
+ {
+ code += 4;
+ length >>= 1;
+ }
- #endregion Instance Fields
+ return code + length;
+ }
- #region Constructors
+ private static int Dcode(int distance)
+ {
+ int code = 0;
+ while (distance >= 4)
+ {
+ code += 2;
+ distance >>= 1;
+ }
+
+ return code + distance;
+ }
+
+ private class Tree
+ {
+ private readonly int minNumCodes;
+ private short[] codes;
+ private readonly int[] bitLengthCounts;
+ private readonly int maxLength;
+ private readonly DeflaterHuffman dh;
public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength)
{
this.dh = dh;
this.minNumCodes = minCodes;
this.maxLength = maxLength;
- freqs = new short[elems];
- bl_counts = new int[maxLength];
+ this.Freqs = new short[elems];
+ this.bitLengthCounts = new int[maxLength];
}
- #endregion Constructors
+ public int NumCodes { get; private set; }
+
+ public short[] Freqs { get; }
+
+ public byte[] Length { get; set; }
///
/// Resets the internal state of the tree
///
public void Reset()
{
- for (int i = 0; i < freqs.Length; i++)
+ for (int i = 0; i < this.Freqs.Length; i++)
{
- freqs[i] = 0;
+ this.Freqs[i] = 0;
}
- codes = null;
- length = null;
+
+ this.codes = null;
+ this.Length = null;
}
public void WriteSymbol(int code)
{
- // if (DeflaterConstants.DEBUGGING) {
- // freqs[code]--;
- // // Console.Write("writeSymbol("+freqs.length+","+code+"): ");
- // }
- dh.pending.WriteBits(codes[code] & 0xffff, length[code]);
+ this.dh.Pending.WriteBits(this.codes[code] & 0xffff, this.Length[code]);
}
///
@@ -129,9 +431,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
public void CheckEmpty()
{
bool empty = true;
- for (int i = 0; i < freqs.Length; i++)
+ for (int i = 0; i < this.Freqs.Length; i++)
{
- empty &= freqs[i] == 0;
+ empty &= this.Freqs[i] == 0;
}
if (!empty)
@@ -147,8 +449,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// length for new codes
public void SetStaticCodes(short[] staticCodes, byte[] staticLengths)
{
- codes = staticCodes;
- length = staticLengths;
+ this.codes = staticCodes;
+ this.Length = staticLengths;
}
///
@@ -156,44 +458,24 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
///
public void BuildCodes()
{
- int numSymbols = freqs.Length;
- int[] nextCode = new int[maxLength];
+ int numSymbols = this.Freqs.Length;
+ int[] nextCode = new int[this.maxLength];
int code = 0;
- codes = new short[freqs.Length];
-
- // if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("buildCodes: "+freqs.Length);
- // }
+ this.codes = new short[this.Freqs.Length];
- for (int bits = 0; bits < maxLength; bits++)
+ for (int bits = 0; bits < this.maxLength; bits++)
{
nextCode[bits] = code;
- code += bl_counts[bits] << (15 - bits);
-
- // if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits]
- // +" nextCode: "+code);
- // }
+ code += this.bitLengthCounts[bits] << (15 - bits);
}
-#if DebugDeflation
- if ( DeflaterConstants.DEBUGGING && (code != 65536) )
- {
- throw new ImageFormatException("Inconsistent bl_counts!");
- }
-#endif
- for (int i = 0; i < numCodes; i++)
+ for (int i = 0; i < this.NumCodes; i++)
{
- int bits = length[i];
+ int bits = this.Length[i];
if (bits > 0)
{
- // if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"),
- // +bits);
- // }
-
- codes[i] = BitReverse(nextCode[bits - 1]);
+ this.codes[i] = BitReverse(nextCode[bits - 1]);
nextCode[bits - 1] += 1 << (16 - bits);
}
}
@@ -201,67 +483,65 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
public void BuildTree()
{
- int numSymbols = freqs.Length;
-
- /* heap is a priority queue, sorted by frequency, least frequent
- * nodes first. The heap is a binary tree, with the property, that
- * the parent node is smaller than both child nodes. This assures
- * that the smallest node is the first parent.
- *
- * The binary tree is encoded in an array: 0 is root node and
- * the nodes 2*n+1, 2*n+2 are the child nodes of node n.
- */
+ int numSymbols = this.Freqs.Length;
+
+ // heap is a priority queue, sorted by frequency, least frequent
+ // nodes first. The heap is a binary tree, with the property, that
+ // the parent node is smaller than both child nodes. This assures
+ // that the smallest node is the first parent.
+ //
+ // The binary tree is encoded in an array: 0 is root node and
+ // the nodes 2*n+1, 2*n+2 are the child nodes of node n.
int[] heap = new int[numSymbols];
int heapLen = 0;
int maxCode = 0;
for (int n = 0; n < numSymbols; n++)
{
- int freq = freqs[n];
+ int freq = this.Freqs[n];
if (freq != 0)
{
// Insert n into heap
int pos = heapLen++;
int ppos;
- while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq)
+ while (pos > 0 && this.Freqs[heap[ppos = (pos - 1) / 2]] > freq)
{
heap[pos] = heap[ppos];
pos = ppos;
}
+
heap[pos] = n;
maxCode = n;
}
}
- /* We could encode a single literal with 0 bits but then we
- * don't see the literals. Therefore we force at least two
- * literals to avoid this case. We don't care about order in
- * this case, both literals get a 1 bit code.
- */
+ // We could encode a single literal with 0 bits but then we
+ // don't see the literals. Therefore we force at least two
+ // literals to avoid this case. We don't care about order in
+ // this case, both literals get a 1 bit code.
while (heapLen < 2)
{
int node = maxCode < 2 ? ++maxCode : 0;
heap[heapLen++] = node;
}
- numCodes = Math.Max(maxCode + 1, minNumCodes);
+ this.NumCodes = Math.Max(maxCode + 1, this.minNumCodes);
int numLeafs = heapLen;
- int[] childs = new int[4 * heapLen - 2];
- int[] values = new int[2 * heapLen - 1];
+ int[] childs = new int[(4 * heapLen) - 2];
+ int[] values = new int[(2 * heapLen) - 1];
int numNodes = numLeafs;
for (int i = 0; i < heapLen; i++)
{
int node = heap[i];
childs[2 * i] = node;
- childs[2 * i + 1] = -1;
- values[i] = freqs[node] << 8;
+ childs[(2 * i) + 1] = -1;
+ values[i] = this.Freqs[node] << 8;
heap[i] = i;
}
- /* Construct the Huffman tree by repeatedly combining the least two
- * frequent nodes.
- */
+ // Construct the Huffman tree by repeatedly combining the least two
+ // frequent nodes.
do
{
int first = heap[0];
@@ -280,17 +560,17 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
heap[ppos] = heap[path];
ppos = path;
- path = path * 2 + 1;
+ path = (path * 2) + 1;
}
- /* Now propagate the last element down along path. Normally
- * it shouldn't go too deep.
- */
+ // Now propagate the last element down along path. Normally
+ // it shouldn't go too deep.
int lastVal = values[last];
while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal)
{
heap[path] = heap[ppos];
}
+
heap[path] = last;
int second = heap[0];
@@ -298,7 +578,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
// Create a new node father of first and second
last = numNodes++;
childs[2 * last] = first;
- childs[2 * last + 1] = second;
+ childs[(2 * last) + 1] = second;
int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);
values[last] = lastVal = values[first] + values[second] - mindepth + 1;
@@ -315,7 +595,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
heap[ppos] = heap[path];
ppos = path;
- path = ppos * 2 + 1;
+ path = (ppos * 2) + 1;
}
// Now propagate the new element down along path
@@ -323,15 +603,17 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
heap[path] = heap[ppos];
}
+
heap[path] = last;
- } while (heapLen > 1);
+ }
+ while (heapLen > 1);
- if (heap[0] != childs.Length / 2 - 1)
+ if (heap[0] != (childs.Length / 2) - 1)
{
throw new ImageFormatException("Heap invariant violated");
}
- BuildLength(childs);
+ this.BuildLength(childs);
}
///
@@ -341,10 +623,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
public int GetEncodedLength()
{
int len = 0;
- for (int i = 0; i < freqs.Length; i++)
+ for (int i = 0; i < this.Freqs.Length; i++)
{
- len += freqs[i] * length[i];
+ len += this.Freqs[i] * this.Length[i];
}
+
return len;
}
@@ -360,10 +643,10 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
int curlen = -1; /* length of current code */
int i = 0;
- while (i < numCodes)
+ while (i < this.NumCodes)
{
count = 1;
- int nextlen = length[i];
+ int nextlen = this.Length[i];
if (nextlen == 0)
{
max_count = 138;
@@ -375,14 +658,15 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
min_count = 3;
if (curlen != nextlen)
{
- blTree.freqs[nextlen]++;
+ blTree.Freqs[nextlen]++;
count = 0;
}
}
+
curlen = nextlen;
i++;
- while (i < numCodes && curlen == length[i])
+ while (i < this.NumCodes && curlen == this.Length[i])
{
i++;
if (++count >= max_count)
@@ -393,19 +677,19 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
if (count < min_count)
{
- blTree.freqs[curlen] += (short)count;
+ blTree.Freqs[curlen] += (short)count;
}
else if (curlen != 0)
{
- blTree.freqs[REP_3_6]++;
+ blTree.Freqs[Repeat3To6]++;
}
else if (count <= 10)
{
- blTree.freqs[REP_3_10]++;
+ blTree.Freqs[Repeat3To10]++;
}
else
{
- blTree.freqs[REP_11_138]++;
+ blTree.Freqs[Repeat11To138]++;
}
}
}
@@ -422,10 +706,10 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
int curlen = -1; // length of current code
int i = 0;
- while (i < numCodes)
+ while (i < this.NumCodes)
{
count = 1;
- int nextlen = length[i];
+ int nextlen = this.Length[i];
if (nextlen == 0)
{
max_count = 138;
@@ -441,10 +725,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
count = 0;
}
}
+
curlen = nextlen;
i++;
- while (i < numCodes && curlen == length[i])
+ while (i < this.NumCodes && curlen == this.Length[i])
{
i++;
if (++count >= max_count)
@@ -462,32 +747,32 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
else if (curlen != 0)
{
- blTree.WriteSymbol(REP_3_6);
- dh.pending.WriteBits(count - 3, 2);
+ blTree.WriteSymbol(Repeat3To6);
+ this.dh.Pending.WriteBits(count - 3, 2);
}
else if (count <= 10)
{
- blTree.WriteSymbol(REP_3_10);
- dh.pending.WriteBits(count - 3, 3);
+ blTree.WriteSymbol(Repeat3To10);
+ this.dh.Pending.WriteBits(count - 3, 3);
}
else
{
- blTree.WriteSymbol(REP_11_138);
- dh.pending.WriteBits(count - 11, 7);
+ blTree.WriteSymbol(Repeat11To138);
+ this.dh.Pending.WriteBits(count - 11, 7);
}
}
}
private void BuildLength(int[] childs)
{
- this.length = new byte[freqs.Length];
+ this.Length = new byte[this.Freqs.Length];
int numNodes = childs.Length / 2;
int numLeafs = (numNodes + 1) / 2;
int overflow = 0;
- for (int i = 0; i < maxLength; i++)
+ for (int i = 0; i < this.maxLength; i++)
{
- bl_counts[i] = 0;
+ this.bitLengthCounts[i] = 0;
}
// First calculate optimal bit lengths
@@ -496,43 +781,36 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
for (int i = numNodes - 1; i >= 0; i--)
{
- if (childs[2 * i + 1] != -1)
+ if (childs[(2 * i) + 1] != -1)
{
int bitLength = lengths[i] + 1;
- if (bitLength > maxLength)
+ if (bitLength > this.maxLength)
{
- bitLength = maxLength;
+ bitLength = this.maxLength;
overflow++;
}
- lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength;
+
+ lengths[childs[2 * i]] = lengths[childs[(2 * i) + 1]] = bitLength;
}
else
{
// A leaf node
int bitLength = lengths[i];
- bl_counts[bitLength - 1]++;
- this.length[childs[2 * i]] = (byte)lengths[i];
+ this.bitLengthCounts[bitLength - 1]++;
+ this.Length[childs[2 * i]] = (byte)lengths[i];
}
}
- // if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("Tree "+freqs.Length+" lengths:");
- // for (int i=0; i < numLeafs; i++) {
- // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
- // + " len: "+length[childs[2*i]]);
- // }
- // }
-
if (overflow == 0)
{
return;
}
- int incrBitLen = maxLength - 1;
+ int incrBitLen = this.maxLength - 1;
do
{
// Find the first bit length which could increase:
- while (bl_counts[--incrBitLen] == 0)
+ while (this.bitLengthCounts[--incrBitLen] == 0)
{
}
@@ -540,426 +818,42 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
// number of overflow nodes.
do
{
- bl_counts[incrBitLen]--;
- bl_counts[++incrBitLen]++;
- overflow -= 1 << (maxLength - 1 - incrBitLen);
- } while (overflow > 0 && incrBitLen < maxLength - 1);
- } while (overflow > 0);
-
- /* We may have overshot above. Move some nodes from maxLength to
- * maxLength-1 in that case.
- */
- bl_counts[maxLength - 1] += overflow;
- bl_counts[maxLength - 2] -= overflow;
-
- /* Now recompute all bit lengths, scanning in increasing
- * frequency. It is simpler to reconstruct all lengths instead of
- * fixing only the wrong ones. This idea is taken from 'ar'
- * written by Haruhiko Okumura.
- *
- * The nodes were inserted with decreasing frequency into the childs
- * array.
- */
+ this.bitLengthCounts[incrBitLen]--;
+ this.bitLengthCounts[++incrBitLen]++;
+ overflow -= 1 << (this.maxLength - 1 - incrBitLen);
+ }
+ while (overflow > 0 && incrBitLen < this.maxLength - 1);
+ }
+ while (overflow > 0);
+
+ // We may have overshot above. Move some nodes from maxLength to
+ // maxLength-1 in that case.
+ this.bitLengthCounts[this.maxLength - 1] += overflow;
+ this.bitLengthCounts[this.maxLength - 2] -= overflow;
+
+ // Now recompute all bit lengths, scanning in increasing
+ // frequency. It is simpler to reconstruct all lengths instead of
+ // fixing only the wrong ones. This idea is taken from 'ar'
+ // written by Haruhiko Okumura.
+ //
+ // The nodes were inserted with decreasing frequency into the childs
+ // array.
int nodePtr = 2 * numLeafs;
- for (int bits = maxLength; bits != 0; bits--)
+ for (int bits = this.maxLength; bits != 0; bits--)
{
- int n = bl_counts[bits - 1];
+ int n = this.bitLengthCounts[bits - 1];
while (n > 0)
{
int childPtr = 2 * childs[nodePtr++];
if (childs[childPtr + 1] == -1)
{
// We found another leaf
- length[childs[childPtr]] = (byte)bits;
+ this.Length[childs[childPtr]] = (byte)bits;
n--;
}
}
}
- // if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("*** After overflow elimination. ***");
- // for (int i=0; i < numLeafs; i++) {
- // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
- // + " len: "+length[childs[2*i]]);
- // }
- // }
- }
- }
-
- #region Instance Fields
-
- ///
- /// Pending buffer to use
- ///
- public DeflaterPendingBuffer pending;
-
- private Tree literalTree;
- private Tree distTree;
- private Tree blTree;
-
- // Buffer for distances
- private short[] d_buf;
-
- private byte[] l_buf;
- private int last_lit;
- private int extra_bits;
-
- #endregion Instance Fields
-
- static DeflaterHuffman()
- {
- // See RFC 1951 3.2.6
- // Literal codes
- staticLCodes = new short[LITERAL_NUM];
- staticLLength = new byte[LITERAL_NUM];
-
- int i = 0;
- while (i < 144)
- {
- staticLCodes[i] = BitReverse((0x030 + i) << 8);
- staticLLength[i++] = 8;
- }
-
- while (i < 256)
- {
- staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
- staticLLength[i++] = 9;
- }
-
- while (i < 280)
- {
- staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
- staticLLength[i++] = 7;
- }
-
- while (i < LITERAL_NUM)
- {
- staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
- staticLLength[i++] = 8;
- }
-
- // Distance codes
- staticDCodes = new short[DIST_NUM];
- staticDLength = new byte[DIST_NUM];
- for (i = 0; i < DIST_NUM; i++)
- {
- staticDCodes[i] = BitReverse(i << 11);
- staticDLength[i] = 5;
- }
- }
-
- ///
- /// Construct instance with pending buffer
- ///
- /// Pending buffer to use
- public DeflaterHuffman(DeflaterPendingBuffer pending)
- {
- this.pending = pending;
-
- literalTree = new Tree(this, LITERAL_NUM, 257, 15);
- distTree = new Tree(this, DIST_NUM, 1, 15);
- blTree = new Tree(this, BITLEN_NUM, 4, 7);
-
- d_buf = new short[BUFSIZE];
- l_buf = new byte[BUFSIZE];
- }
-
- ///
- /// Reset internal state
- ///
- public void Reset()
- {
- last_lit = 0;
- extra_bits = 0;
- literalTree.Reset();
- distTree.Reset();
- blTree.Reset();
- }
-
- ///
- /// Write all trees to pending buffer
- ///
- /// The number/rank of treecodes to send.
- public void SendAllTrees(int blTreeCodes)
- {
- blTree.BuildCodes();
- literalTree.BuildCodes();
- distTree.BuildCodes();
- pending.WriteBits(literalTree.numCodes - 257, 5);
- pending.WriteBits(distTree.numCodes - 1, 5);
- pending.WriteBits(blTreeCodes - 4, 4);
- for (int rank = 0; rank < blTreeCodes; rank++)
- {
- pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);
- }
- literalTree.WriteTree(blTree);
- distTree.WriteTree(blTree);
-
-#if DebugDeflation
- if (DeflaterConstants.DEBUGGING) {
- blTree.CheckEmpty();
- }
-#endif
- }
-
- ///
- /// Compress current buffer writing data to pending buffer
- ///
- public void CompressBlock()
- {
- for (int i = 0; i < last_lit; i++)
- {
- int litlen = l_buf[i] & 0xff;
- int dist = d_buf[i];
- if (dist-- != 0)
- {
- // if (DeflaterConstants.DEBUGGING) {
- // Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");
- // }
-
- int lc = Lcode(litlen);
- literalTree.WriteSymbol(lc);
-
- int bits = (lc - 261) / 4;
- if (bits > 0 && bits <= 5)
- {
- pending.WriteBits(litlen & ((1 << bits) - 1), bits);
- }
-
- int dc = Dcode(dist);
- distTree.WriteSymbol(dc);
-
- bits = dc / 2 - 1;
- if (bits > 0)
- {
- pending.WriteBits(dist & ((1 << bits) - 1), bits);
- }
- }
- else
- {
- // if (DeflaterConstants.DEBUGGING) {
- // if (litlen > 32 && litlen < 127) {
- // Console.Write("("+(char)litlen+"): ");
- // } else {
- // Console.Write("{"+litlen+"}: ");
- // }
- // }
- literalTree.WriteSymbol(litlen);
- }
- }
-
-#if DebugDeflation
- if (DeflaterConstants.DEBUGGING) {
- Console.Write("EOF: ");
- }
-#endif
- literalTree.WriteSymbol(EOF_SYMBOL);
-
-#if DebugDeflation
- if (DeflaterConstants.DEBUGGING) {
- literalTree.CheckEmpty();
- distTree.CheckEmpty();
- }
-#endif
- }
-
- ///
- /// Flush block to output with no compression
- ///
- /// Data to write
- /// Index of first byte to write
- /// Count of bytes to write
- /// True if this is the last block
- public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
- {
-#if DebugDeflation
- // if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("Flushing stored block "+ storedLength);
- // }
-#endif
- pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
- pending.AlignToByte();
- pending.WriteShort(storedLength);
- pending.WriteShort(~storedLength);
- pending.WriteBlock(stored, storedOffset, storedLength);
- Reset();
- }
-
- ///
- /// Flush block to output with compression
- ///
- /// Data to flush
- /// Index of first byte to flush
- /// Count of bytes to flush
- /// True if this is the last block
- public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
- {
- literalTree.freqs[EOF_SYMBOL]++;
-
- // Build trees
- literalTree.BuildTree();
- distTree.BuildTree();
-
- // Calculate bitlen frequency
- literalTree.CalcBLFreq(blTree);
- distTree.CalcBLFreq(blTree);
-
- // Build bitlen tree
- blTree.BuildTree();
-
- int blTreeCodes = 4;
- for (int i = 18; i > blTreeCodes; i--)
- {
- if (blTree.length[BL_ORDER[i]] > 0)
- {
- blTreeCodes = i + 1;
- }
- }
- int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() +
- literalTree.GetEncodedLength() + distTree.GetEncodedLength() +
- extra_bits;
-
- int static_len = extra_bits;
- for (int i = 0; i < LITERAL_NUM; i++)
- {
- static_len += literalTree.freqs[i] * staticLLength[i];
- }
- for (int i = 0; i < DIST_NUM; i++)
- {
- static_len += distTree.freqs[i] * staticDLength[i];
- }
- if (opt_len >= static_len)
- {
- // Force static trees
- opt_len = static_len;
- }
-
- if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3)
- {
- // Store Block
-
- // if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len
- // + " <= " + static_len);
- // }
- FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
- }
- else if (opt_len == static_len)
- {
- // Encode with static tree
- pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3);
- literalTree.SetStaticCodes(staticLCodes, staticLLength);
- distTree.SetStaticCodes(staticDCodes, staticDLength);
- CompressBlock();
- Reset();
- }
- else
- {
- // Encode with dynamic tree
- pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3);
- SendAllTrees(blTreeCodes);
- CompressBlock();
- Reset();
- }
- }
-
- ///
- /// Get value indicating if internal buffer is full
- ///
- /// true if buffer is full
- public bool IsFull()
- {
- return last_lit >= BUFSIZE;
- }
-
- ///
- /// Add literal to buffer
- ///
- /// Literal value to add to buffer.
- /// Value indicating internal buffer is full
- public bool TallyLit(int literal)
- {
- // if (DeflaterConstants.DEBUGGING) {
- // if (lit > 32 && lit < 127) {
- // //Console.WriteLine("("+(char)lit+")");
- // } else {
- // //Console.WriteLine("{"+lit+"}");
- // }
- // }
- d_buf[last_lit] = 0;
- l_buf[last_lit++] = (byte)literal;
- literalTree.freqs[literal]++;
- return IsFull();
- }
-
- ///
- /// Add distance code and length to literal and distance trees
- ///
- /// Distance code
- /// Length
- /// Value indicating if internal buffer is full
- public bool TallyDist(int distance, int length)
- {
- // if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("[" + distance + "," + length + "]");
- // }
-
- d_buf[last_lit] = (short)distance;
- l_buf[last_lit++] = (byte)(length - 3);
-
- int lc = Lcode(length - 3);
- literalTree.freqs[lc]++;
- if (lc >= 265 && lc < 285)
- {
- extra_bits += (lc - 261) / 4;
- }
-
- int dc = Dcode(distance - 1);
- distTree.freqs[dc]++;
- if (dc >= 4)
- {
- extra_bits += dc / 2 - 1;
- }
- return IsFull();
- }
-
- ///
- /// Reverse the bits of a 16 bit value.
- ///
- /// Value to reverse bits
- /// Value with bits reversed
- public static short BitReverse(int toReverse)
- {
- return (short)(bit4Reverse[toReverse & 0xF] << 12 |
- bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
- bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
- bit4Reverse[toReverse >> 12]);
- }
-
- private static int Lcode(int length)
- {
- if (length == 255)
- {
- return 285;
}
-
- int code = 257;
- while (length >= 8)
- {
- code += 4;
- length >>= 1;
- }
- return code + length;
- }
-
- private static int Dcode(int distance)
- {
- int code = 0;
- while (distance >= 4)
- {
- code += 2;
- distance >>= 1;
- }
- return code + distance;
}
}
}