public void Encode(Stream input, Stream output, IEnumerable <Match> matches, IHuffmanTreeBuilder treeBuilder) { var block = new Block(); var matchArray = matches.ToArray(); var rawValueTree = CreateRawValueTree(input, matchArray, treeBuilder); block.rawValueDictionary = rawValueTree.GetHuffCodes().ToDictionary(node => node.Item1, node => node.Item2); block.countIndexes = GetCountIndexes(matchArray, input.Length); var countIndexValueTree = CreateIndexValueTree(block, treeBuilder); block.countIndexDictionary = countIndexValueTree.GetHuffCodes().ToDictionary(node => node.Item1, node => node.Item2); block.dispIndexes = GetDispIndexes(matchArray); var dispIndexTree = CreateDisplacementIndexTree(block, treeBuilder); block.dispIndexDictionary = dispIndexTree.GetHuffCodes().ToDictionary(node => node.Item1, node => node.Item2); using var bw = new BitWriter(output, BitOrder.LeastSignificantBitFirst, 1, ByteOrder.LittleEndian); // Without obfuscation bw.WriteByte(0x02); WriteTreeNode(bw, rawValueTree, 8); WriteTreeNode(bw, countIndexValueTree, 6); WriteTreeNode(bw, dispIndexTree, 5); var countPosition = 0; var displacementPosition = 0; foreach (var match in matchArray) { // Compress raw data if (input.Position < match.Position) { CompressRawData(input, bw, block, (int)(match.Position - input.Position), ref countPosition); } // Compress match CompressMatchData(input, bw, block, match, ref countPosition, ref displacementPosition); } // Compress raw data if (input.Position < input.Length) { CompressRawData(input, bw, block, (int)(input.Length - input.Position), ref countPosition); } // Write final 0 index foreach (var bit in block.countIndexDictionary[block.countIndexes.Last()]) { bw.WriteBit(bit - '0'); } }
public void Dispose() { _countIndexes = null; _dispIndexes = null; _rawValueDictionary = null; _countIndexDictionary = null; _dispIndexDictionary = null; _treeBuilder = null; _matchParser?.Dispose(); _matchParser = null; }
public void Encode(Stream input, Stream output, IHuffmanTreeBuilder treeBuilder) { if (input.Length > 0xFFFFFF) { throw new InvalidOperationException("Data to compress is too long."); } var compressionHeader = new[] { (byte)(0x20 + _bitDepth), (byte)input.Length, (byte)((input.Length >> 8) & 0xFF), (byte)((input.Length >> 16) & 0xFF) }; output.Write(compressionHeader, 0, 4); _encoder.Encode(input, output, treeBuilder); }
public void Encode(Stream input, Stream output, IHuffmanTreeBuilder treeBuilder) { if (input.Length > 0x1FFFFFFF) { throw new InvalidOperationException("Data to compress is too long."); } var huffmanMode = _bitDepth == 4 ? 2 : 3; var compressionHeader = new[] { (byte)((byte)(input.Length << 3) | huffmanMode), (byte)(input.Length >> 5), (byte)(input.Length >> 13), (byte)(input.Length >> 21) }; output.Write(compressionHeader, 0, 4); _encoder.Encode(input, output, treeBuilder); }
public NintendoHuffmanEncoder(int bitDepth, ByteOrder byteOrder, IHuffmanTreeBuilder treeBuilder) { _bitDepth = bitDepth; _treeBuilder = treeBuilder; _byteOrder = byteOrder; }
private HuffmanTreeNode CreateDisplacementIndexTree(Block block, IHuffmanTreeBuilder treeBuilder) { return(treeBuilder.Build(block.dispIndexes, 8, NibbleOrder.LowNibbleFirst)); }
private HuffmanTreeNode CreateIndexValueTree(Block block, IHuffmanTreeBuilder treeBuilder) { return(treeBuilder.Build(block.countIndexes, 8, NibbleOrder.LowNibbleFirst)); }
private HuffmanTreeNode CreateRawValueTree(Stream input, Match[] matches, IHuffmanTreeBuilder treeBuilder) { var huffmanInput = RemoveMatchesFromInput(input.ToArray(), matches); return(treeBuilder.Build(huffmanInput, 8, NibbleOrder.LowNibbleFirst)); }
public TaikoLz81Encoder(IMatchParser matchParser, IHuffmanTreeBuilder treeBuilder) { _matchParser = matchParser; _treeBuilder = treeBuilder; }
public HuffmanHeaderlessEncoder(int bitDepth, NibbleOrder nibbleOrder, IHuffmanTreeBuilder treeBuilder) { _bitDepth = bitDepth; _treeBuilder = treeBuilder; _nibbleOrder = nibbleOrder; }
public HuffmanEncoder(int bitDepth, IHuffmanTreeBuilder treeBuilder, NibbleOrder nibbleOrder = NibbleOrder.LowNibbleFirst) { _bitDepth = bitDepth; _encoder = new HuffmanHeaderlessEncoder(bitDepth, nibbleOrder, treeBuilder); }
public void Encode(Stream input, Stream output, IHuffmanTreeBuilder treeBuilder) { var rootNode = treeBuilder.Build(input.ToArray(), _bitDepth, _nibbleOrder); // For a more even distribution of the children over the branches, we'll label the tree nodes var labelList = LabelTreeNodes(rootNode); // Create huffman bit codes var bitCodes = labelList[0].GetHuffCodes().ToDictionary(node => node.Item1, node => node.Item2); using var bw = new BinaryWriterX(output, true); // Write header bw.Write((byte)labelList.Count); // Write Huffman tree foreach (var node in labelList.Take(1).Concat(labelList.SelectMany(node => node.Children))) { if (node.Children != null) { node.Code |= node.Children.Select((child, i) => child.IsLeaf ? (byte)(0x80 >> i) : 0).Sum(); } bw.Write((byte)node.Code); } // Write bits to stream using var bitWriter = new BitWriter(bw.BaseStream, BitOrder.MostSignificantBitFirst, 4, ByteOrder.LittleEndian); switch (_bitDepth) { case 4: while (input.Position < input.Length) { var value = input.ReadByte(); if (_nibbleOrder == NibbleOrder.LowNibbleFirst) { foreach (var bit in bitCodes[value % 16]) { bitWriter.WriteBit(bit - '0'); } foreach (var bit in bitCodes[value / 16]) { bitWriter.WriteBit(bit - '0'); } } else { foreach (var bit in bitCodes[value / 16]) { bitWriter.WriteBit(bit - '0'); } foreach (var bit in bitCodes[value % 16]) { bitWriter.WriteBit(bit - '0'); } } } break; case 8: while (input.Position < input.Length) { var value = input.ReadByte(); foreach (var bit in bitCodes[value]) { bitWriter.WriteBit(bit - '0'); } } break; } bitWriter.Flush(); }
public void Dispose() { _treeBuilder = null; _matchParser?.Dispose(); _matchParser = null; }