// ============================================================= // Code // ============================================================= public byte[] Compress(byte[] input) { Output = new BitEncoder(); Matcher = new HashChain8(input, 26, 32); for (int i = 0; i < SymbolProbabilities.Length; i++) { SymbolProbabilities[i].Init(); } for (int i = 0; i < DistanceScaleProbabilities.Length; i++) { DistanceScaleProbabilities[i].Init(); } int inputSize = input.Length; int inputOffset = 1; EncodeSymbol(input[0], 0); // Emit the first byte as a literal with no context. while (inputOffset <= inputSize) { var match = FindBestMatch(inputOffset); bool matchAvailable = match.Benefit > 0; if (matchAvailable) { var nextMatch = PeekNextMatch(inputOffset + 1); if (nextMatch.Benefit > match.Benefit) { matchAvailable = false; } } if (matchAvailable) { if (matchAvailable) { if (match.Length > 255) { match.Length = 255; } EncodeSymbol(256 + match.Length, input[inputOffset - 1]); EncodeDistance(match.Distance); inputOffset += match.Length; } } else { EncodeSymbol(input[inputOffset], input[inputOffset - 1]); inputOffset++; } if (inputOffset == inputSize) { break; } } return(Output.GetBytes()); }
private static StringBuilder DoCompress(string input, DataEncoding encoding) { if (input == "") { return(null); } else { var result = new StringBuilder(); if (null == input) { return(result); } else { var encoder = new BitEncoder(result, encoding); var compressor = new Compressor(encoder); compressor.Compress(input); compressor.MarkEndOfStream(); return(result); } } }
public void Encode(Stream internalStream) { #region Validation if (internalStream == null) { throw new ArgumentNullException(nameof(internalStream), "You need to provide a stream."); } #endregion //If it's the first step. var isFirst = true; var clearFlag = (1 << ColorDepth); var endOfFileFlag = clearFlag + 1; var codeTable = new Dictionary <string, int>(); //Number of indexes of the currently processed bytes. var releaseCount = 0; var codeSize = (byte)(ColorDepth + 1); var availableCode = endOfFileFlag + 1; var maskCode = (1 << codeSize) - 1; var bitEncoder = new BitEncoder(codeSize); //Initial code size. internalStream.WriteByte((byte)ColorDepth); //First thing being added. bitEncoder.Add(clearFlag); int suffix = 0; while (releaseCount < IndexedPixels.Length) { #region If it's the first byte if (isFirst) { //The first time, the suffix is set to the first index bytes. suffix = IndexedPixels[releaseCount++]; //If it's the last one. if (releaseCount == IndexedPixels.Length) { bitEncoder.Add(suffix); bitEncoder.Add(endOfFileFlag); bitEncoder.End(); internalStream.WriteByte((byte)(bitEncoder.Length)); internalStream.Write(bitEncoder.OutList.ToArray(), 0, bitEncoder.Length); bitEncoder.OutList.Clear(); break; } isFirst = false; continue; } #endregion #region Before and after the change, and the constituent entities var prefix = suffix; suffix = IndexedPixels[releaseCount++]; string entry = $"{prefix},{suffix}"; #endregion #region If you do not know the current entity, entities encoded, and output the prefix if (!codeTable.ContainsKey(entry)) { //If the current entity is not encoded, then output the prefix bitEncoder.Add(prefix); //And the current entity is encoded. Inserts and after that adds the availableCode count. codeTable.Add(entry, availableCode++); if (availableCode > (MaxStackSize - 3)) { //Insert the clear tag, reinvent codeTable.Clear(); ColorDepth = InitDataSize; codeSize = (byte)(ColorDepth + 1); availableCode = endOfFileFlag + 1; maskCode = (1 << codeSize) - 1; bitEncoder.Add(clearFlag); bitEncoder.InBit = codeSize; } else if (availableCode > (1 << codeSize)) { //If the current code is greater than the current code available to represent values ColorDepth++; codeSize = (byte)(ColorDepth + 1); bitEncoder.InBit = codeSize; maskCode = (1 << codeSize) - 1; } //Divides into more blocks. if (bitEncoder.Length >= 255) { //Size of the block. internalStream.WriteByte(255); //Writes the 255 sized block. internalStream.Write(bitEncoder.OutList.ToArray(), 0, 255); if (bitEncoder.Length > 255) { var leftBuffer = new byte[bitEncoder.Length - 255]; //Removes the last written 255 bytes. bitEncoder.OutList.CopyTo(255, leftBuffer, 0, leftBuffer.Length); bitEncoder.OutList.Clear(); bitEncoder.OutList.AddRange(leftBuffer); } else { bitEncoder.OutList.Clear(); } } } #endregion #region If you know the current entity, set the suffixes to the current index value of an entity else { //Set the suffix to the current entity encoding suffix = codeTable[entry]; } #endregion //if (releaseCount == 40240) // suffix = suffix; #region To the end of an image, writes over identity, and outputs the current codes left in the data stream if (releaseCount == IndexedPixels.Length) { bitEncoder.Add(suffix); //Adds the last sufix. bitEncoder.Add(endOfFileFlag); //End of the LZW bitEncoder.End(); //If the block size if greater than 255, divides into two. if (bitEncoder.Length > 255) { var leftBuffer = new byte[bitEncoder.Length - 255]; bitEncoder.OutList.CopyTo(255, leftBuffer, 0, leftBuffer.Length); bitEncoder.OutList.Clear(); bitEncoder.OutList.AddRange(leftBuffer); internalStream.WriteByte((byte)leftBuffer.Length); internalStream.Write(leftBuffer, 0, leftBuffer.Length); } else { internalStream.WriteByte((byte)(bitEncoder.Length)); internalStream.Write(bitEncoder.OutList.ToArray(), 0, bitEncoder.Length); bitEncoder.OutList.Clear(); } break; } #endregion } //For 3 weeks I forgot to add this little piece of sh*t, my gifs were always corrupted... //Signals the end of the list of blocks. internalStream.WriteByte(0); }
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex, Encoder rangeEncoder, int NumBitLevels, UInt32 symbol) { UInt32 m = 1; for (int i = 0; i < NumBitLevels; i++) { UInt32 bit = symbol & 1; Models[startIndex + m].Encode(rangeEncoder, bit); m = (m << 1) | bit; symbol >>= 1; } }
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex, int NumBitLevels, UInt32 symbol) { UInt32 price = 0; UInt32 m = 1; for (int i = NumBitLevels; i > 0; i--) { UInt32 bit = symbol & 1; symbol >>= 1; price += Models[startIndex + m].GetPrice(bit); m = (m << 1) | bit; } return price; }
public static void ReverseEncode(BitEncoder[] models, uint startIndex, Encoder rangeEncoder, int numBitLevels, uint symbol) { uint m = 1; for (var i = 0; i < numBitLevels; i++) { var bit = symbol & 1; models[startIndex + m].Encode(rangeEncoder, bit); m = (m << 1) | bit; symbol >>= 1; } }
public static uint ReverseGetPrice(BitEncoder[] models, uint startIndex, int numBitLevels, uint symbol) { uint price = 0; uint m = 1; for (var i = numBitLevels; i > 0; i--) { var bit = symbol & 1; symbol >>= 1; price += models[startIndex + m].GetPrice(bit); m = (m << 1) | bit; } return price; }
/// <summary> /// Encodes the compressed indexed pixel data to the given stream. /// </summary> /// <param name="stream">The stream to add the data to.</param> /// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception> public void Encode(Stream stream) { Guard.NotNull(stream, nameof(stream)); // Whether it is a first step. bool first = true; // The initial suffix. int suffix = 0; // Indicator to reinitialize the code table. int clearCode = 1 << this.colorDepth; // End of information code int endOfInformation = clearCode + 1; // The code table for storing encoded colors. Dictionary<string, int> codeTable = new Dictionary<string, int>(); // The current number of index bytes processed. int releaseCount = 0; // Calculate the code available. byte codeSize = (byte)(this.colorDepth + 1); int availableCode = endOfInformation + 1; // Initialise. BitEncoder bitEncoder = new BitEncoder(codeSize); stream.WriteByte(this.colorDepth); bitEncoder.Add(clearCode); while (releaseCount < this.indexedPixels.Length) { if (first) { // If this is the first byte the suffix is set to the first byte index. suffix = this.indexedPixels[releaseCount++]; if (releaseCount == this.indexedPixels.Length) { bitEncoder.Add(suffix); bitEncoder.Add(endOfInformation); bitEncoder.End(); stream.WriteByte((byte)bitEncoder.Length); stream.Write(bitEncoder.ToArray(), 0, bitEncoder.Length); bitEncoder.Clear(); break; } first = false; continue; } // Switch int prefix = suffix; // Read the bytes at the index. suffix = this.indexedPixels[releaseCount++]; // Acts as a key for code table entries. string key = $"{prefix},{suffix}"; // Is index buffer + the index in our code table? if (!codeTable.ContainsKey(key)) { // If the current entity is not coded add the prefix. bitEncoder.Add(prefix); // Add the current bytes codeTable.Add(key, availableCode++); if (availableCode > (MaxStackSize - 3)) { // Clear out and reset the wheel. codeTable.Clear(); this.colorDepth = this.initDataSize; codeSize = (byte)(this.colorDepth + 1); availableCode = endOfInformation + 1; bitEncoder.Add(clearCode); bitEncoder.IntitialBit = codeSize; } else if (availableCode > (1 << codeSize)) { // If the currently available coding is greater than the current value. // the coded bits can represent. this.colorDepth++; codeSize = (byte)(this.colorDepth + 1); bitEncoder.IntitialBit = codeSize; } if (bitEncoder.Length >= 255) { stream.WriteByte(255); stream.Write(bitEncoder.ToArray(), 0, 255); if (bitEncoder.Length > 255) { byte[] leftBuffer = new byte[bitEncoder.Length - 255]; bitEncoder.CopyTo(255, leftBuffer, 0, leftBuffer.Length); bitEncoder.Clear(); bitEncoder.AddRange(leftBuffer); } else { bitEncoder.Clear(); } } } else { // Set the suffix to the current byte. suffix = codeTable[key]; } // Output code for contents of index buffer. // Output end-of-information code. if (releaseCount == this.indexedPixels.Length) { bitEncoder.Add(suffix); bitEncoder.Add(endOfInformation); bitEncoder.End(); if (bitEncoder.Length > 255) { byte[] leftBuffer = new byte[bitEncoder.Length - 255]; bitEncoder.CopyTo(255, leftBuffer, 0, leftBuffer.Length); bitEncoder.Clear(); bitEncoder.AddRange(leftBuffer); stream.WriteByte((byte)leftBuffer.Length); stream.Write(leftBuffer, 0, leftBuffer.Length); } else { stream.WriteByte((byte)bitEncoder.Length); stream.Write(bitEncoder.ToArray(), 0, bitEncoder.Length); bitEncoder.Clear(); } break; } } }