public void TestArrayRebuild() { var sourceBytes = new byte[2]; sourceBytes[0] = 100; //0110 0100 sourceBytes[1] = 54; //0011 0110 var bitStreamManager = new BitStreamManager(sourceBytes); Assert.AreEqual(16, bitStreamManager.Lenght); byte[] rebuildBytes = bitStreamManager.ToByteArray(); Assert.AreEqual(sourceBytes[0], rebuildBytes[0]); Assert.AreEqual(sourceBytes[1], rebuildBytes[1]); }
public void TestC() { // else if (highestPaletteIndex >= 16 && highestPaletteIndex <= 31) //{ // paletteBitSize = 5;//max 31 values; BitStreamManager bs = new BitStreamManager(); bs.AddBit(true); bs.AddBit(false); bs.AddByte(28, 5); byte[] values = bs.ToByteArray(); bs = new BitStreamManager(values); Assert.IsTrue(bs.ReadBit()); Assert.IsFalse(bs.ReadBit()); Assert.AreEqual(28, bs.ReadValue(6)); //Assert.IsFalse(bs.ReadBit()); }
public void TestArrayBuildFromBitPopulated() { var bitStreamManager = new BitStreamManager(); //100 = 0110 0100 bitStreamManager.AddBit(false); bitStreamManager.AddBit(false); bitStreamManager.AddBit(true); bitStreamManager.AddBit(false); bitStreamManager.AddBit(false); bitStreamManager.AddBit(true); bitStreamManager.AddBit(true); bitStreamManager.AddBit(false); //54 = 0011 0110 bitStreamManager.AddBit(false); bitStreamManager.AddBit(true); bitStreamManager.AddBit(true); bitStreamManager.AddBit(false); bitStreamManager.AddBit(true); bitStreamManager.AddBit(true); //Deixa esses dois em branco, e o bitStream tem que preencher com 0s... //bitStreamManager.AddBit(false); //bitStreamManager.AddBit(false); var sourceBytes = new byte[2]; sourceBytes[0] = 100; //0110 0100 sourceBytes[1] = 54; // Assert.AreEqual(14, bitStreamManager.Lenght); byte[] rebuildBytes = bitStreamManager.ToByteArray(); Assert.AreEqual(sourceBytes[0], rebuildBytes[0]); Assert.AreEqual(sourceBytes[1], rebuildBytes[1]); }
private StripData EncodeUncompressed() { var strip = new StripData(); var bitStream = new BitStreamManager(); strip.CodecId = 0x01; _renderdingDirection = strip.RenderdingDirection; _currentLocation.X = 0; _currentLocation.Y = 0; int firstPaletteIndex = FindTableIndex(_imageToEncode.GetPixel(_currentOffset + 0, 0)); bitStream.AddByte((byte)firstPaletteIndex); while (!(_currentLocation.X == 7 && _currentLocation.Y == (_height - 1))) { var paletteIndex = FindTableIndex(GetNextPixel()); bitStream.AddByte((byte)paletteIndex); } strip.ImageData = bitStream.ToByteArray(); return(strip); }
private void Encode() { if (_imageToEncode.Width != _pictureData.Width || _imageToEncode.Height != _pictureData.Height) { throw new ImageEncodeException("The image must have the same size as original costume frame"); } var bitStreamManager = new BitStreamManager(); int colorSize = 0; int repetitionCountSize = 0; int maxRepetitionCountValue = 0; if (_costume.PaletteSize == 16) { colorSize = 4; repetitionCountSize = 4; maxRepetitionCountValue = 15; //1111 } else { colorSize = 5; repetitionCountSize = 3; maxRepetitionCountValue = 7; //111 } int currentLine = 0; int currentColumn = 0; Color currentColor = _imageToEncode.GetPixel(0, 0); byte currentColorPalette = GetRelativePaletteIndex(currentColor); int repetitionCount = 0; /* The compression used for the costume data is a simple byte based RLE compression. * However, it works by columns, not by lines. * Each byte contains the color in the high bits and the repetition count in the low bits. * If the repetition count is 0, then the next byte contains the actual repetition count. * How many bits are used for the color depends on the palette size: for a 16 color palette, 4 bits are used for the color; for 32 colors, 5 bits are used. */ while (!(currentLine == 0 && currentColumn == _pictureData.Width)) { Color newColor = _imageToEncode.GetPixel(currentColumn, currentLine); if (newColor == currentColor) { repetitionCount++; } else { while (repetitionCount > 255) { //write the repetition count in the next byte bitStreamManager.AddByte(0, repetitionCountSize); bitStreamManager.AddByte(currentColorPalette, colorSize); bitStreamManager.AddByte(255); repetitionCount -= 255; } if (repetitionCount > maxRepetitionCountValue) { //write the repetition count in the next byte bitStreamManager.AddByte(0, repetitionCountSize); bitStreamManager.AddByte(currentColorPalette, colorSize); bitStreamManager.AddByte((byte)repetitionCount); } else { bitStreamManager.AddByte((byte)repetitionCount, repetitionCountSize); bitStreamManager.AddByte(currentColorPalette, colorSize); } currentColor = newColor; currentColorPalette = GetRelativePaletteIndex(currentColor); repetitionCount = 1; } currentLine++; if (currentLine == _pictureData.Height) { currentLine = 0; currentColumn++; } } if (repetitionCount > 0) { while (repetitionCount > 255) { //write the repetition count in the next byte bitStreamManager.AddByte(0, repetitionCountSize); bitStreamManager.AddByte(currentColorPalette, colorSize); bitStreamManager.AddByte(255); repetitionCount -= 255; } if (repetitionCount > maxRepetitionCountValue) { //write the repetition count in the next byte bitStreamManager.AddByte(0, repetitionCountSize); bitStreamManager.AddByte(currentColorPalette, colorSize); bitStreamManager.AddByte((byte)repetitionCount); } else { bitStreamManager.AddByte((byte)repetitionCount, repetitionCountSize); bitStreamManager.AddByte(currentColorPalette, colorSize); } } _pictureData.ImageData = bitStreamManager.ToByteArray(); }
// lines // encoded size : 16le // line data : size bytes private void Encode() { var result = new List <byte>(); _currentLine = 0; //Primeira passagem - Cadastra tudo alternado while (_currentLine < (_height)) { var bitStream = new BitStreamManager(); var lineInformation = new List <SegmentInformation>(); var currentSegmentInformation = new SegmentInformation(); byte lastColorIndex = (byte)FindTableIndex(_imageToEncode.GetPixel(0, _currentLine)); if (lastColorIndex == (byte)FindTableIndex(_imageToEncode.GetPixel(1, _currentLine))) { currentSegmentInformation.RepeatSameColor = true; } currentSegmentInformation.Colors.Add(lastColorIndex); for (int x = 1; x < _width; x++) { byte currentColorIndex = (byte)FindTableIndex(_imageToEncode.GetPixel(x, _currentLine)); if (currentColorIndex != lastColorIndex) { if (currentSegmentInformation.RepeatSameColor) { //Mudou de REPETIR para NÃO REPETIR lineInformation.Add(currentSegmentInformation); currentSegmentInformation = new SegmentInformation(); currentSegmentInformation.RepeatSameColor = false; } } else { if (!currentSegmentInformation.RepeatSameColor) { //Mudou de NÃO REPETIR para REPETIR lineInformation.Add(currentSegmentInformation); currentSegmentInformation = new SegmentInformation(); currentSegmentInformation.RepeatSameColor = true; } } currentSegmentInformation.Colors.Add(currentColorIndex); lastColorIndex = currentColorIndex; } lineInformation.Add(currentSegmentInformation); //Segunda passagem - verifica a lista de itens não repetidos para ver se o ultimo elemento é um elemento da lista repetida seguinte. for (int i = 1; i < lineInformation.Count; i++) { var previous = lineInformation[i - 1]; var previousLastIndex = previous.Colors.Count - 1; var current = lineInformation[i - 1]; if (!previous.RepeatSameColor && current.RepeatSameColor && previous.Colors[previousLastIndex] == current.Colors[0]) { //move o item da lista anterior para a lista atual current.Colors.Insert(0, previous.Colors[previousLastIndex]); previous.Colors.RemoveAt(previousLastIndex); } } //Terceira passagem - procura por listas que eventualmente ficaram vazias, e as remove. //É importante percorrer a lista ao contrários, caso contrário a lista sera lida errada, além de dar IndexOutOfBounds no final. for (int i = lineInformation.Count - 1; i >= 0; i--) { if (lineInformation[i].Colors.Count == 0) { lineInformation.RemoveAt(i); } } //Quarta passagem, divide as listas com mais de 128 itens em varias listas, pois 128 é o limite máximo de 7 bits + 1. var finalLineInformation = new List <SegmentInformation>(); foreach (SegmentInformation segmentInformation in lineInformation) { if (segmentInformation.Colors.Count > 128) { while (segmentInformation.Colors.Count > 128) { var dividedLineInformation = new SegmentInformation(); dividedLineInformation.RepeatSameColor = segmentInformation.RepeatSameColor; dividedLineInformation.Colors.AddRange(segmentInformation.Colors.Take(128).ToArray()); finalLineInformation.Add(dividedLineInformation); segmentInformation.Colors = segmentInformation.Colors.Skip(128).ToList(); } } finalLineInformation.Add(segmentInformation); } //Quinta passagem, grava o BitStream. foreach (SegmentInformation segmentInformation in finalLineInformation) { bitStream.AddBit(segmentInformation.RepeatSameColor); if (segmentInformation.RepeatSameColor) { bitStream.AddByte((byte)(segmentInformation.Colors.Count - 1), 7); bitStream.AddByte(segmentInformation.Colors[0]); } else { bitStream.AddByte((byte)(segmentInformation.Colors.Count - 1), 7); foreach (byte differentLine in segmentInformation.Colors) { bitStream.AddByte(differentLine); } } } _currentLine++; byte[] encodedLine = bitStream.ToByteArray(); result.AddRange(BinaryHelper.UInt16ToBytes((ushort)encodedLine.Length)); result.AddRange(encodedLine); } _imageBomp.Data = result.ToArray(); }
private StripData EncodeCompressedMethod2() { var strip = new StripData(); var bitStream = new BitStreamManager(); bool transparent; int paletteSize; VerifyStrip(out transparent, out paletteSize, true); bool alternateCode = EncodeSettings == EncodeTypeSettings.Method2AlternateCode; strip.CodecId = (byte)(GetSubstractionCode(transparent, true, CompressionTypes.Method2, alternateCode) + paletteSize); if (strip.CompressionType == CompressionTypes.Unknow) { strip.CodecId = (byte)(GetSubstractionCode(transparent, true, CompressionTypes.Method2, !alternateCode) + paletteSize); } _renderdingDirection = strip.RenderdingDirection; _currentLocation.X = 0; _currentLocation.Y = 0; //Color currentColor = GetNextPixel(); //pq isso fica menos errado!? Color currentColor = _imageToEncode.GetPixel(_currentOffset + 0, 0); int currentPaletteIndex = FindTableIndex(currentColor); bitStream.AddByte((byte)currentPaletteIndex); byte accumulatedSameColor = 0; while (!(_currentLocation.X == 7 && _currentLocation.Y == (_height - 1))) { var newPaletteIndex = FindTableIndex(GetNextPixel()); if (newPaletteIndex == currentPaletteIndex) { accumulatedSameColor++; //Add one to the count of pixels with the same color. if (accumulatedSameColor == 255) { //If we have pixels with the previous color drawed before the color change //We need to write that information to the data, before process the new color. WriteAccumulatedColor(bitStream, accumulatedSameColor); accumulatedSameColor = 0; } } else { if (accumulatedSameColor > 0) { //If we have pixels with the previous color drawed before the color change //We need to write that information to the data, before process the new color. WriteAccumulatedColor(bitStream, accumulatedSameColor); accumulatedSameColor = 0; } /* * Then discory the new bit code. * * 10: Read a new palette index from the bitstream (i.e., the number of bits specified by the parameter), and draw the next pixel. * 11: Read the next 3 bit value, and perform an action, depending on the value: * 000 (0): Decrease current palette index by 4. * 001 (1): Decrease current palette index by 3. * 010 (2): Decrease current palette index by 2. * 011 (3): Decrease current palette index by 1. * 100 (4): Read next 8 bits. Draw the number of pixels specified by these 8 bits with the current palette index (somewhat similar to RLE). * 101 (5): Increase current palette index by 1. * 110 (6): Increase current palette index by 2. * 111 (7): Increase current palette index by 3. */ bitStream.AddBit(true); //Add the change action bit if ((newPaletteIndex < (currentPaletteIndex - 4)) || (newPaletteIndex > (currentPaletteIndex + 3))) { //reset the negation value, read the next index from the palette, //and draw the pixel. bitStream.AddBit(false); bitStream.AddByte((byte)newPaletteIndex, paletteSize); } else { //Add the read code bit bitStream.AddBit(true); if (newPaletteIndex == (currentPaletteIndex - 4)) //000 (0): Decrease current palette index by 4. { //Add the code 0 bitStream.AddByte(0, 3); } else if (newPaletteIndex == (currentPaletteIndex - 3)) //001 (1): Decrease current palette index by 3. { //Add the code 1 bitStream.AddByte(1, 3); } else if (newPaletteIndex == (currentPaletteIndex - 2)) //010 (2): Decrease current palette index by 2. { //Add the code 2 bitStream.AddByte(2, 3); } else if (newPaletteIndex == (currentPaletteIndex - 1)) //011 (3): Decrease current palette index by 1. { //Add the code 3 bitStream.AddByte(3, 3); } else if (newPaletteIndex == (currentPaletteIndex + 1)) //101 (5): Increase current palette index by 1. { //Add the code 5 bitStream.AddByte(5, 3); } else if (newPaletteIndex == (currentPaletteIndex + 2)) //110 (6): Increase current palette index by 2. { //Add the code 6 bitStream.AddByte(6, 3); } else if (newPaletteIndex == (currentPaletteIndex + 3)) //111 (7): Increase current palette index by 3. { //Add the code 7 bitStream.AddByte(7, 3); } else { throw new ImageEncodeException("nao podia ter caido aqui"); } } currentPaletteIndex = newPaletteIndex; } } //if the loop terminated with accumulated bits pending, add these to the stream. if (accumulatedSameColor > 0) { //If we have pixels with the previous color drawed before the color change //We need to write that information to the data, before process the new color. WriteAccumulatedColor(bitStream, accumulatedSameColor); } strip.ImageData = bitStream.ToByteArray(); return(strip); }
private StripData EncodeCompressedMethod1(bool horizontalDirection) { var strip = new StripData(); var bitStream = new BitStreamManager(); bool transparent; int paletteSize; VerifyStrip(out transparent, out paletteSize, true); strip.CodecId = (byte)(GetSubstractionCode(transparent, horizontalDirection, CompressionTypes.Method1) + paletteSize); _renderdingDirection = strip.RenderdingDirection; _currentLocation.X = 0; _currentLocation.Y = 0; int negationValue = 1; //Color currentColor = GetNextPixel(); //pq isso fica menos errado!? Color currentColor = _imageToEncode.GetPixel(_currentOffset + 0, 0); int currentPaletteIndex = FindTableIndex(currentColor); bitStream.AddByte((byte)currentPaletteIndex); while (!(_currentLocation.X == 7 && _currentLocation.Y == (_height - 1))) { var newPaletteIndex = FindTableIndex(GetNextPixel()); if (newPaletteIndex == currentPaletteIndex) { bitStream.AddBit(false); //continue Drawing the same color. } else { bitStream.AddBit(true); //discover what to do. if (newPaletteIndex == (currentPaletteIndex - negationValue)) { //subtract the negation value from the palette and draw the next pixel; bitStream.AddBit(true); bitStream.AddBit(false); } else if (newPaletteIndex == (currentPaletteIndex - (negationValue * -1))) { //invert the negation value, subtract it from the palette //and draw the next pixel; negationValue *= -1; bitStream.AddBit(true); bitStream.AddBit(true); } else { //reset the negation value, read the next index from the palette, //and draw the pixel. negationValue = 1; bitStream.AddBit(false); bitStream.AddByte((byte)newPaletteIndex, paletteSize); } currentPaletteIndex = newPaletteIndex; } } strip.ImageData = bitStream.ToByteArray(); return(strip); }
private ZPlaneStripData EncodeZPlaneStrip() { var strip = new ZPlaneStripData(); var bitStream = new BitStreamManager(); var linesInformation = new List <LineInformation>(); _currentLine = 0; var currentLineInformation = new LineInformation(); byte lastLine = GetNextLine(); if (lastLine == PeekNextLine()) { currentLineInformation.RepeatSameLine = true; } currentLineInformation.Lines.Add(lastLine); //Primeira passagem - Cadastra tudo alternado while (_currentLine < (_height)) { byte currentLine = GetNextLine(); if (currentLine != lastLine) { if (currentLineInformation.RepeatSameLine) { //Mudou de REPETIR para NÃO REPETIR linesInformation.Add(currentLineInformation); currentLineInformation = new LineInformation(); currentLineInformation.RepeatSameLine = false; } } else { if (!currentLineInformation.RepeatSameLine) { //Mudou de NÃO REPETIR para REPETIR linesInformation.Add(currentLineInformation); currentLineInformation = new LineInformation(); currentLineInformation.RepeatSameLine = true; } } currentLineInformation.Lines.Add(currentLine); lastLine = currentLine; } linesInformation.Add(currentLineInformation); //Segunda passagem - verifica a lista de itens não repetidos para ver se o ultimo elemento é um elemento da lista repetida seguinte. for (int i = 1; i < linesInformation.Count; i++) { var previous = linesInformation[i - 1]; var previousLastIndex = previous.Lines.Count - 1; var current = linesInformation[i - 1]; if (!previous.RepeatSameLine && current.RepeatSameLine && previous.Lines[previousLastIndex] == current.Lines[0]) { //move o item da lista anterior para a lista atual current.Lines.Insert(0, previous.Lines[previousLastIndex]); previous.Lines.RemoveAt(previousLastIndex); } } //Terceira passagem - procura por listas que eventualmente ficaram vazias, e as remove. //É importante percorrer a lista ao contrários, caso contrário a lista sera lida errada, além de dar IndexOutOfBounds no final. for (int i = linesInformation.Count - 1; i >= 0; i--) { if (linesInformation[i].Lines.Count == 0) { linesInformation.RemoveAt(i); } } //Quarta passagem, divide as listas com mais de 127 itens em varias listas, pois 127 é o limite máximo de 7 bits. var finalLinesInformation = new List <LineInformation>(); foreach (LineInformation lineInformation in linesInformation) { if (lineInformation.Lines.Count > 127) { while (lineInformation.Lines.Count > 127) { var dividedLineInformation = new LineInformation(); dividedLineInformation.RepeatSameLine = lineInformation.RepeatSameLine; dividedLineInformation.Lines.AddRange(lineInformation.Lines.Take(127).ToArray()); finalLinesInformation.Add(dividedLineInformation); lineInformation.Lines = lineInformation.Lines.Skip(127).ToList(); } } finalLinesInformation.Add(lineInformation); } //Quinta passagem, grava o BitStream. foreach (LineInformation lineInformation in finalLinesInformation) { if (lineInformation.RepeatSameLine) { byte repeatByte = BinaryHelper.Compose2Bytes(1, (byte)lineInformation.Lines.Count, 7); bitStream.AddByte(repeatByte); bitStream.AddByte(lineInformation.Lines[0]); } else { //Verifica se o different line não tinha apenas 1 linha antes de gravar a informação, isso pode acontecer //em situações onde a linha 1 e 2 são A e 3 e 4 são B, por exemplo. byte repeatByte = BinaryHelper.Compose2Bytes(0, (byte)lineInformation.Lines.Count, 7); bitStream.AddByte(repeatByte); foreach (byte differentLine in lineInformation.Lines) { bitStream.AddByte(differentLine); } } } strip.ImageData = bitStream.ToByteArray(); return(strip); }