private static void buildCodeTable(Dictionary <CodeTableEntry, ushort> codeTable, byte startCodeSize) { codeTable.Clear(); // startCodeSize has a max of 8, so it will always fit into a byte var colorCodes = getColorCodeCount(startCodeSize); for (byte code = 0; code < colorCodes; ++code) { codeTable.Add(CodeTableEntry.MakeColorEntry(code), code); } codeTable.Add(CodeTableEntry.Clear, (ushort)codeTable.Count); codeTable.Add(CodeTableEntry.EndOfInformation, (ushort)codeTable.Count); }
private static void buildCodeTable(List <CodeTableEntry> codeTable, byte startCodeSize) { codeTable.Clear(); // startCodeSize has a max of 8, so it will always fit into a byte var colorCodes = getColorCodeCount(startCodeSize); for (byte code = 0; code < colorCodes; ++code) { codeTable.Add(CodeTableEntry.MakeColorEntry(code)); } codeTable.Add(CodeTableEntry.Clear); codeTable.Add(CodeTableEntry.EndOfInformation); }
/// <summary> /// Gets the decompressed Color Data starting from the current position in the <see cref="Stream"/>. /// </summary> /// <param name="stream">The <see cref="Stream"/> containing the compressed Color Data.</param> /// <returns>The decompressed Color Data.</returns> public static byte[] Decode(Stream stream) { var startCodeSize = (byte)stream.ReadByte(); if (startCodeSize < minStartCodeSize || startCodeSize > maxStartCodeSize) { throw new ArgumentOutOfRangeException("startCodeSize", "The encoded start code size has to be between 2 and 8!"); } var indexStream = new List <byte>(); var codeData = GifDataStream.Decode(stream); using (var codeStream = new BitStream.BitStream(new MemoryStream(codeData))) { var codeTable = new List <CodeTableEntry>(); buildCodeTable(codeTable, startCodeSize); var codeSize = startCodeSize + 1u; var indexBuffer = new List <byte>(); CodeTableEntry codeEntry; ushort prevCode = getColorCodeCount(startCodeSize); var first = true; do { var codeBytes = new byte[2]; codeStream.ReadBits(codeBytes, 0, codeSize); var code = BitConverter.ToUInt16(codeBytes, 0); if (code < codeTable.Count) { codeEntry = codeTable[code]; if (codeEntry == CodeTableEntry.Clear) { indexBuffer.Clear(); buildCodeTable(codeTable, startCodeSize); first = true; } else if (codeEntry != CodeTableEntry.EndOfInformation) { indexStream.AddRange(codeTable[code].Colors); if (!first) { indexBuffer.Clear(); indexBuffer.AddRange(codeTable[prevCode].Colors); indexBuffer.Add(codeTable[code].Colors[0]); codeTable.Add(CodeTableEntry.MakeColorEntry(indexBuffer.ToArray())); } first = false; } } else if (code == codeTable.Count) { indexBuffer.Clear(); indexBuffer.AddRange(codeTable[prevCode].Colors); indexBuffer.Add(codeTable[prevCode].Colors[0]); codeEntry = CodeTableEntry.MakeColorEntry(indexBuffer.ToArray()); codeTable.Add(codeEntry); indexStream.AddRange(codeTable[code].Colors); } else { throw new ArgumentOutOfRangeException("code", "Encoded code was too large. Expected: " + codeTable.Count + " or less; got: " + code); } if (Math.Pow(2, codeSize) <= codeTable.Count) { ++codeSize; } prevCode = code; }while (codeEntry != CodeTableEntry.EndOfInformation); } return(indexStream.ToArray()); }
/// <summary> /// Writes the compressed version of the given Color Data to the given <see cref="Stream"/>. /// </summary> /// <param name="stream">The <see cref="Stream"/> to write to.</param> /// <param name="colorData">The Color Data to compress.</param> /// <param name="colorTableSize">Number of entries in the used color table.</param> public static void Encode(Stream stream, IEnumerable <byte> colorData, ushort colorTableSize) { var startCodeSize = (byte)Math.Max(minStartCodeSize, Math.Ceiling(Math.Log(colorTableSize, 2))); if (startCodeSize > maxStartCodeSize) { throw new ArgumentOutOfRangeException("colorTableSize", "Color Table can have a maximum of 256 entries!"); } stream.WriteByte(startCodeSize); using (var codeStream = new BitStream.BitStream(new MemoryStream())) { var codeTable = new Dictionary <CodeTableEntry, ushort>(); buildCodeTable(codeTable, startCodeSize); var codeSize = (byte)(startCodeSize + 1); codeStream.WriteBits(BitConverter.GetBytes(codeTable[CodeTableEntry.Clear]), 0, codeSize); var indexBuffer = new List <byte>(colorData.Take(1)); CodeTableEntry tableEntry = null; foreach (var color in colorData.Skip(1)) { if (codeSize > maxCodeSize) { codeStream.WriteBits(BitConverter.GetBytes(codeTable[CodeTableEntry.Clear]), 0, maxCodeSize); buildCodeTable(codeTable, startCodeSize); codeSize = (byte)(startCodeSize + 1); } var prevIndexBuffer = indexBuffer.ToArray(); indexBuffer.Add(color); tableEntry = CodeTableEntry.MakeColorEntry(indexBuffer.ToArray()); if (codeTable.ContainsKey(tableEntry)) { continue; } codeTable.Add(tableEntry, (ushort)codeTable.Count); var bytes = BitConverter.GetBytes(codeTable[CodeTableEntry.MakeColorEntry(prevIndexBuffer)]); codeStream.WriteBits(bytes, 0, codeSize); indexBuffer.Clear(); indexBuffer.Add(color); if ((Math.Pow(2, codeSize) + 1) <= codeTable.Count) { ++codeSize; } } if (codeTable.ContainsKey(tableEntry)) { codeStream.WriteBits(BitConverter.GetBytes(codeTable[tableEntry]), 0, codeSize); } else { codeStream.WriteBits(BitConverter.GetBytes(codeTable[CodeTableEntry.MakeColorEntry(indexBuffer.ToArray())]), 0, codeSize); } codeStream.WriteBits(BitConverter.GetBytes(codeTable[CodeTableEntry.EndOfInformation]), 0, codeSize); codeStream.WriteBits(0, (BitNum)(BitNum.MaxValue - codeStream.BitPosition)); var codes = ((MemoryStream)codeStream.UnderlayingStream).ToArray(); GifDataStream.Encode(stream, codes); } }
private byte[] decompressLZW() { List <byte> pdata = new List <byte>(); current = readByte(); //int posout = 0; nextbit = 0; CodeTableEntry[] codetable = new CodeTableEntry[4096]; byte[] decodestack = new byte[4096]; int stackptr = 0; uint n_bits = 9; uint free_entry = 257; uint oldcode = getBits(n_bits); uint lastbyte = oldcode; uint bitpos = 0; //tw.WriteLine("pdata["+pdata.Count+"] = " + oldcode); pdata.Add((byte)oldcode); try { while (offset < data.Length) { uint newcode = getBits(n_bits); bitpos += n_bits; if (newcode == 256) { uint nbits3 = n_bits << 3; uint nskip = (nbits3 - ((bitpos - 1) % nbits3)) - 1; uint dummy = getBits(nskip); n_bits = 9; free_entry = 256; bitpos = 0; } else { uint code = newcode; if (code >= free_entry) { if (stackptr >= 4096) { break; } decodestack[stackptr] = (byte)lastbyte; stackptr++; code = oldcode; } while (code >= 256) { if (code > 4095) { break; } decodestack[stackptr] = codetable[code].append; stackptr++; code = codetable[code].prefix; } decodestack[stackptr] = (byte)code; stackptr++; lastbyte = code; while (stackptr > 0) { stackptr--; //tw.WriteLine("pdata[" + pdata.Count + "] = " + decodestack[stackptr]); pdata.Add(decodestack[stackptr]); } if (free_entry < 4096) { codetable[free_entry].prefix = (ushort)oldcode; codetable[free_entry].append = (byte)lastbyte; free_entry++; int temp = 1 << (int)n_bits; if (free_entry >= temp && n_bits < 12) { n_bits++; bitpos = 0; } } oldcode = newcode; } } } catch { } // Throw away exception and return data return(pdata.ToArray()); }