public void EncodeImage( Bitmap inp, Stream outs ) { if ( inp == null || outs == null ) return; int width = inp.Width; int height = inp.Height; if ( width < 1 || height < 1 ) return; // !!!{{ TODO: add the encoding code here DeflateStream ds = new BufferedDeflateStream( 16384, outs, CompressionMode.Compress, true ); // file header: [ MAGIC, width, height ] ds.WriteByte( (byte)((MAGIC >> 24) & 0xff) ); ds.WriteByte( (byte)((MAGIC >> 16) & 0xff) ); ds.WriteByte( (byte)((MAGIC >> 8) & 0xff) ); ds.WriteByte( (byte)( MAGIC & 0xff) ); ds.WriteByte( (byte)((width >> 8) & 0xff) ); ds.WriteByte( (byte)( width & 0xff) ); ds.WriteByte( (byte)((height >> 8) & 0xff) ); ds.WriteByte( (byte)( height & 0xff) ); for ( int y = 0; y < height; y++ ) for ( int x = 0; x < width; x++ ) { byte gr = (byte)(inp.GetPixel( x, y ).GetBrightness() * 255.0f); ds.WriteByte( gr ); } ds.Close(); // !!!}} }
public void EncodeImage(Bitmap inputImage, Stream outputStream) { if (inputImage == null || outputStream == null) return; int width = inputImage.Width; int height = inputImage.Height; if (width < 1 || height < 1) return; int backgroundColor = ComputeDominantColor(inputImage); Bitmap copyImage = new Bitmap(inputImage); DeflateStream ds = new BufferedDeflateStream(16384, outputStream, CompressionMode.Compress, true); try { // file header: [ MAGIC, width, height, dominant color ] ds.WriteByte((byte)((MAGIC >> 24) & 0xff)); ds.WriteByte((byte)((MAGIC >> 16) & 0xff)); ds.WriteByte((byte)((MAGIC >> 8) & 0xff)); ds.WriteByte((byte)(MAGIC & 0xff)); ds.WriteByte((byte)((width >> 8) & 0xff)); ds.WriteByte((byte)(width & 0xff)); ds.WriteByte((byte)((height >> 8) & 0xff)); ds.WriteByte((byte)(height & 0xff)); // dominant color ds.WriteByte((byte)(backgroundColor & 0x01)); // debug counters: int totalPixels = width * height; if (InfoEnabled) { Console.WriteLine("Total pixels: {0}, [{1}, {2}]", totalPixels, width, height); } int totalLinePixels = GetTotalLinePixels(inputImage, backgroundColor); if (InfoEnabled) { Console.WriteLine("Total line pixels: {0} ({1} %)", totalLinePixels, 100.0 * totalLinePixels / totalPixels); } int firstLinePixels = 0; int neighborhoodLinePixels = 0; int totalStartPixelBits = 0; Point previousStartingPoint = new Point(); int longestLine = 0; List<int> lineDirections = new List<int>(); if (TraceEnabled) { Console.WriteLine("Encoding."); } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int bwIntensity = BWImageHelper.GetBWPixel(copyImage, x, y); if (IsBackground(backgroundColor, bwIntensity)) { continue; } // now we have found the first unprocessed non-background pixel if (TraceEnabled) { Console.WriteLine("First pixel: [{0}, {1}]", x, y); } BWImageHelper.SetBWPixel(copyImage, x, y, backgroundColor); // write position of line's starting pixel // X and Y as two-byte numbers int diffX = x - previousStartingPoint.X; int diffY = y - previousStartingPoint.Y; firstLinePixels++; int currentX = x; int currentY = y; previousStartingPoint.X = x; previousStartingPoint.Y = y; bool lineContinues = true; int lineLength = 1; while (lineContinues && (lineLength < 256)) //while (lineContinues) { lineContinues = false; for (int directionIndex = 0; directionIndex < neighborhood.Directions.Count; directionIndex++) { Point direction = neighborhood.Directions[directionIndex]; int nextX = currentX + direction.X; int nextY = currentY + direction.Y; if (!BWImageHelper.IsInside(copyImage, nextX, nextY)) { continue; } int nextIntensity = BWImageHelper.GetBWPixel(copyImage, nextX, nextY); if (!IsBackground(backgroundColor, nextIntensity)) { currentX = nextX; currentY = nextY; if (TraceEnabled) { Console.WriteLine("Neighbor pixel: [{0}, {1}]", nextX, nextY); Console.WriteLine(" Direction: {0} ({1})", direction, directionIndex); } lineDirections.Add(directionIndex); lineContinues = true; neighborhoodLinePixels++; lineLength++; BWImageHelper.SetBWPixel(copyImage, nextX, nextY, backgroundColor); break; } } } // store diffX and diffY as two signed 15-bit numbers in 4 bytes // |1-bit X sign|15-bit abs(diffX)|1-bit Y sign|15-bit abs(diffY)| // sign: 0 = positive or zero, 1 = negative if (TraceEnabled) { Console.WriteLine("Diff: [{0}, {1}]", diffX, diffY); } // X sign int buffer = (diffX < 0) ? 1 : 0; // diff X buffer <<= 15; buffer |= Math.Abs(diffX) & 0x1fff; // Y sign buffer <<= 1; buffer |= (diffY < 0) ? 1 : 0; // diff Y buffer <<= 15; buffer |= Math.Abs(diffY) & 0x1fff; ds.WriteByte((byte)((buffer >> 24) & 0xff)); ds.WriteByte((byte)((buffer >> 16) & 0xff)); ds.WriteByte((byte)((buffer >> 8) & 0xff)); ds.WriteByte((byte)(buffer & 0xff)); totalStartPixelBits += CountBits(buffer); // write the number of following directions ds.WriteByte((byte)((lineLength - 1) & 0xff)); // write the list of following directions buffer = 0; int bufferLength = 0; foreach (int directionIndex in lineDirections) { buffer = (buffer << neighborhood.SignificantBits) + directionIndex; bufferLength += neighborhood.SignificantBits; int remainingBits = bufferLength - 8; // free space in the byte if ((bufferLength >= 8) && (remainingBits < neighborhood.SignificantBits)) { int writtenByte = (buffer >> remainingBits) & 0xff; ds.WriteByte((byte)(writtenByte & 0xff)); buffer -= writtenByte << remainingBits; bufferLength -= 8; } } if (bufferLength > 0) { // shift the remaining bits completely to the left // (so that the rest of the byte is filled with zeros only) buffer <<= 8 - bufferLength; ds.WriteByte((byte)(buffer & 0xff)); buffer = 0; bufferLength = 0; } lineDirections.Clear(); longestLine = Math.Max(longestLine, lineLength); } } if (InfoEnabled) { Console.WriteLine("Total first pixels: {0} ({1} %) ({2} %)", firstLinePixels, 100.0 * firstLinePixels / totalPixels, 100.0 * firstLinePixels / totalLinePixels); Console.WriteLine("Total neighborhood pixels: {0} ({1} %) ({2} %)", neighborhoodLinePixels, 100.0 * neighborhoodLinePixels / totalPixels, 100.0 * neighborhoodLinePixels / totalLinePixels); Console.WriteLine("First + neighborhood: {0}", firstLinePixels + neighborhoodLinePixels); Console.WriteLine("Total start pixel bits: {0}", totalStartPixelBits); Console.WriteLine("Longest line: {0}", longestLine); Console.WriteLine(); } } finally { if (ds != null) { ds.Close(); } } }