private unsafe void RefreshCachedBitmap(IBitmap frameBitmap) { this.bitmap.Lock(); if (frameBitmap is BitmapRGB24) { var bmp24 = frameBitmap as BitmapRGB24; fixed(void *ptr = &bmp24.Pixels[0]) { IntPtr buffer = new IntPtr(ptr); this.bitmap.WritePixels(new Int32Rect(0, 0, bmp24.Width, bmp24.Height), buffer, bmp24.Pixels.Length * 3, bmp24.Width * 3); } } else if (frameBitmap is BitmapRGB32) { var bmp32 = frameBitmap as BitmapRGB32; fixed(void *ptr = &bmp32.Pixels[0]) { IntPtr buffer = new IntPtr(ptr); this.bitmap.WritePixels(new Int32Rect(0, 0, bmp32.Width, bmp32.Height), buffer, bmp32.Pixels.Length * sizeof(ColorRGB32), bmp32.Width * 4); } } else { var bmp = frameBitmap as BitmapRGB; var src = bmp.Pixels; var pix = new ColorRGB32[bmp.Size.Elements]; for (int i = 0; i < pix.Length; i++) { var p = src[i]; pix[i] = new ColorRGB32(p.Red, p.Green, p.Blue, p.Alpha); } fixed(void *ptr = &pix[0]) { IntPtr buffer = new IntPtr(ptr); this.bitmap.WritePixels(new Int32Rect(0, 0, bmp.Width, bmp.Height), buffer, bmp.Pixels.Length * sizeof(ColorRGB32), bmp.Width * sizeof(ColorRGB32)); } } this.bitmap.AddDirtyRect(new Int32Rect(0, 0, this.bitmap.PixelWidth, this.bitmap.PixelHeight)); this.bitmap.Unlock(); this.Dispatcher.Invoke(DispatcherPriority.Render, EmptyAction); }
public override void Decode(Frame output) { int width = 0, height = 0; byte depth = 0; PNGColorType colorType = PNGColorType.TruecolorWithAlpha; Frame result = output; // TODO: Verify signature // Pull the PNG into a data buffer. if (this.Bitstream == null || this.Bitstream.Length < 1) return; var bytes = new byte[this.Bitstream.Length]; this.Bitstream.Read(bytes, 0, bytes.Length); var buf = new DataBuffer(bytes, ByteOrder.BigEndian); var signature = buf.ReadInt64(); if (signature != PNGCodec.BitstreamSignature) { } bool ihdrDone = false; //bool iendDone = false; using (var pixelStream = new MemoryStream()) { var zout = new ZOutputStream(pixelStream); // Start reading chunks. while (buf.Available > 0) { int length = buf.ReadInt32(); string chunk = string.Concat((char)buf.ReadByte(), (char)buf.ReadByte(), (char)buf.ReadByte(), (char)buf.ReadByte()); switch (chunk) { case "IHDR": if (ihdrDone) throw new NotImplementedException(); else ihdrDone = true; if (length != 13) throw new NotImplementedException(); width = buf.ReadInt32(); height = buf.ReadInt32(); depth = buf.ReadByte(); colorType = (PNGColorType)buf.ReadByte(); byte xmethod = buf.ReadByte(); PNGFilterMethod filterMethod = (PNGFilterMethod)buf.ReadByte(); byte interlaceMethod = buf.ReadByte(); break; case "IDAT": var data = buf.ReadBytes(length); zout.Write(data, 0, data.Length); break; default: Console.WriteLine("Skipping unknown chunk \"{0}\" in PNG bitstream at offset {1}", chunk, (buf.Position - 8).ToString("X")); buf.Position += (length > buf.Available) ? buf.Available : length; break; } int crc32 = buf.ReadInt32(); } if (depth == 8) { if (colorType == PNGColorType.TruecolorWithAlpha) { //var pd = new byte[width * height * 4]; var pd = new byte[pixelStream.Length]; pixelStream.Position = 0; pixelStream.Read(pd, 0, pd.Length); ColorRGB32[] pix = new ColorRGB32[width * height]; ColorRGB32 p = new ColorRGB32(); //File.WriteAllBytes("dump.bin", pd); for (int i = 0, n = 0; i < pix.Length; i++) { if (i % width == 0) n++; p.Red = pd[n++]; p.Green = pd[n++]; p.Blue = pd[n++]; p.Alpha = pd[n++]; pix[i] = p; } result.Video[0] = new BitmapRGB32(width, height, pix); } else if (colorType == PNGColorType.Truecolor) { //var pd = new byte[width * height * 3]; var pd = new byte[pixelStream.Length]; pixelStream.Position = 0; pixelStream.Read(pd, 0, pd.Length); ColorRGB24[] pix = new ColorRGB24[width * height]; ColorRGB24 p = new ColorRGB24(); //File.WriteAllBytes("dump.bin", pd); for (int i = 0, n = 0; i < pix.Length; i++) { if (i % width == 0) n++; p.Red = pd[n++]; p.Green = pd[n++]; p.Blue = pd[n++]; pix[i] = p; } result.Video[0] = new BitmapRGB24(width, height, pix); } else { throw new NotImplementedException(); } } else { throw new NotImplementedException(); } } }
private void DecodeBitmap() { var dc = this.context; if (dc.Stage < TGADecodeStage.FooterDecoded) { this.DecodeFooter(dc); } var header = dc.Header; // Syntax sugar int w = dc.Header.Width; int h = dc.Header.Height; if (w < 1 || h < 1) { throw new NotImplementedException(); } if (header.BitsPerPixel % 8 != 0) { throw new NotImplementedException("BitsPerPixel not multiple of 8"); } // Number of bytes per scanline int stride = header.Width * (header.BitsPerPixel / 8); // Read all the bytes that contain pixel data var data = new byte[dc.PixelDataLength]; this.Bitstream.Seek(dc.PixelDataOffset, SeekOrigin.Begin); this.Bitstream.Read(data, 0, data.Length); if (header.ColorMapType == TGAColorMapType.ColorMapped) // Read color map data { throw new NotImplementedException(); } else if (header.ImageType == TGAImageType.UncompressedTrueColor) { if (header.BitsPerPixel == 16) { throw new NotImplementedException(); // TODO: Implement support for 16-bit TGA decoding. } else if (header.BitsPerPixel == 24) { // Create an array of all the pixels in the bitmap (width x height). var pixels = new ColorRGB24[w * h]; // ...and assign it to the Bitmap that will eventually be returned. dc.DecodedBitmap = new BitmapRGB24(w, h, pixels); var n = -1; if (dc.PixelOrder == TGAPixelOrder.BottomLeft) { var line = new ColorRGB24[w]; for (int y = h; y > 0; --y) { for (int x = 0; x < line.Length; ++x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; } line.CopyTo(pixels, (y - 1) * line.Length); } } else if (dc.PixelOrder == TGAPixelOrder.BottomRight) { var line = new ColorRGB24[w]; // BTT + Right-to-Left (RTL) pixel order. for (int y = h; y > 0; --y) { // Iterate over the pixels in the scanline from right-to-left. for (int x = line.Length - 1; x >= 0; --x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; } line.CopyTo(pixels, (y - 1) * line.Length); } } else if (dc.PixelOrder == TGAPixelOrder.TopLeft) { // Top-to-bottom (TTB) + LTR pixel order. for (int i = 0; i < pixels.Length; i++) { // All pixels can be decoded in one pass; TTB + LTR is the way bitmaps are laid out in memory. pixels[i].Blue = data[++n]; pixels[i].Green = data[++n]; pixels[i].Red = data[++n]; } } else if (dc.PixelOrder == TGAPixelOrder.TopRight) { var line = new ColorRGB24[w]; for (int y = 0; y < h; ++y) { for (int x = line.Length - 1; x >= 0; --x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; } line.CopyTo(pixels, y * line.Length); } } else { throw new NotImplementedException(); } } else if (header.BitsPerPixel == 32) // Same as above, plus alpha channel. { // Create an array of all the pixels in the bitmap (width x height). var pixels = new ColorRGB32[w * h]; // ...and assign it to the Bitmap that will eventually be returned. dc.DecodedBitmap = new BitmapRGB32(w, h, pixels); int n = -1; var line = new ColorRGB32[w]; // Most common scanline direction first; TGA stores scanlines bottom-to-top by default. if (dc.PixelOrder == TGAPixelOrder.BottomLeft) { // Bottom-to-top (BTT) + Left-to-right (LTR) pixel order. for (int y = h; y > 0; --y) { for (int x = 0; x < line.Length; ++x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; line[x].Alpha = data[++n]; } line.CopyTo(pixels, (y - 1) * line.Length); } } else if (dc.PixelOrder == TGAPixelOrder.BottomRight) { for (int y = h; y > 0; --y) { // Iterate over the pixels in the scanline from right-to-left. for (int x = line.Length - 1; x >= 0; --x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; line[x].Alpha = data[++n]; } line.CopyTo(pixels, (y - 1) * line.Length); } } else if (dc.PixelOrder == TGAPixelOrder.TopLeft) { for (int i = 0; i < pixels.Length; ++i) { // All pixels can be decoded in one pass; TTB + LTR is the way bitmaps are laid out in memory. pixels[i].Blue = data[++n]; pixels[i].Green = data[++n]; pixels[i].Red = data[++n]; pixels[i].Alpha = data[++n]; } } else if (dc.PixelOrder == TGAPixelOrder.TopRight) { for (int y = 0; y < h; ++y) { for (int x = line.Length - 1; x >= 0; --x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; line[x].Alpha = data[++n]; } line.CopyTo(pixels, y * line.Length); } } } } else if (header.ImageType == TGAImageType.RunLengthEncodedTrueColor) { int n = -1; bool raw = false; byte p; if (header.BitsPerPixel == 16) { throw new NotImplementedException(); } if (header.BitsPerPixel == 24) { // Create an array of all the pixels in the bitmap (width x height). var pixels = new ColorRGB24[w * h]; // ...and assign it to the Bitmap that will eventually be returned. dc.DecodedBitmap = new BitmapRGB24(w, h, pixels); ColorRGB24 px = new ColorRGB24(); // Operate on a line-by-line basis; RLE packets will never wrap from one scanline to another. var line = new ColorRGB24[w]; // Most common scanline direction first; TGA stores scanlines bottom-to-top by default. if (dc.PixelOrder == TGAPixelOrder.BottomLeft) { for (int y = h; y > 0; --y) { for (int x = 0, e = 0; x < line.Length; ++x, --e) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } line[x] = px; } line.CopyTo(pixels, (y - 1) * w); } } else if (dc.PixelOrder == TGAPixelOrder.BottomRight) { for (int y = h; y > 0; --y) { for (int x = w, e = 0; x >= 0; --x, --e) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } line[x] = px; } line.CopyTo(pixels, (y - 1) * w); } } else if (dc.PixelOrder == TGAPixelOrder.TopLeft) { for (int i = 0, e = 0; i < pixels.Length; ++i) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } pixels[i] = px; } } else if (dc.PixelOrder == TGAPixelOrder.TopRight) { throw new NotImplementedException(); /* * for (int y = 0; y < h; y++) * { * for (int x = w - 1; x >= 0; x--) * { * if (e == 0) * { * // Read the "packet header" * p = data[++n]; * // Highest bit of packet header indicates RLE (1) or RAW (0). * raw = (p & 0x80) != 0x80; * // Remaining 7 bits indicate RLE packet length. * e = 1 + (p & 0x7F); * * // Read color * px.Blue = data[++n]; * px.Green = data[++n]; * px.Red = data[++n]; * } * else if (raw) * { * px.Blue = data[++n]; * px.Green = data[++n]; * px.Red = data[++n]; * } * * line[x] = px; * } * }*/ } } else if (header.BitsPerPixel == 32) // Just like above, but with an alpha channel. { // Create an array of all the pixels in the bitmap (width x height). var pixels = new ColorRGB32[w * h]; // ...and assign it to the Bitmap that will eventually be returned. dc.DecodedBitmap = new BitmapRGB32(w, h, pixels); ColorRGB32 px = new ColorRGB32(); // Operate on a line-by-line basis; RLE packets will never wrap from one scanline to another. var line = new ColorRGB32[w]; var len = line.Length; if (dc.PixelOrder == TGAPixelOrder.BottomLeft) { for (int y = h; y > 0; --y) { for (int x = 0, e = 0; x < len; ++x, --e) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; px.Alpha = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; px.Alpha = data[++n]; } line[x] = px; } line.CopyTo(pixels, (y - 1) * w); } } else if (dc.PixelOrder == TGAPixelOrder.BottomRight) { throw new NotImplementedException(); } else if (dc.PixelOrder == TGAPixelOrder.TopLeft) { throw new NotImplementedException(); } else if (dc.PixelOrder == TGAPixelOrder.TopRight) { throw new NotImplementedException(); } } else { throw new NotImplementedException(); } } dc.Stage = TGADecodeStage.BitmapDecoded; }
public override void Decode(Frame output) { int width = 0, height = 0; byte depth = 0; PNGColorType colorType = PNGColorType.TruecolorWithAlpha; Frame result = output; // TODO: Verify signature // Pull the PNG into a data buffer. if (this.Bitstream == null || this.Bitstream.Length < 1) { return; } var bytes = new byte[this.Bitstream.Length]; this.Bitstream.Read(bytes, 0, bytes.Length); var buf = new DataBuffer(bytes, ByteOrder.BigEndian); var signature = buf.ReadInt64(); if (signature != PNGCodec.BitstreamSignature) { } bool ihdrDone = false; //bool iendDone = false; using (var pixelStream = new MemoryStream()) { var zout = new ZOutputStream(pixelStream); // Start reading chunks. while (buf.Available > 0) { int length = buf.ReadInt32(); string chunk = string.Concat((char)buf.ReadByte(), (char)buf.ReadByte(), (char)buf.ReadByte(), (char)buf.ReadByte()); switch (chunk) { case "IHDR": if (ihdrDone) { throw new NotImplementedException(); } else { ihdrDone = true; } if (length != 13) { throw new NotImplementedException(); } width = buf.ReadInt32(); height = buf.ReadInt32(); depth = buf.ReadByte(); colorType = (PNGColorType)buf.ReadByte(); byte xmethod = buf.ReadByte(); PNGFilterMethod filterMethod = (PNGFilterMethod)buf.ReadByte(); byte interlaceMethod = buf.ReadByte(); break; case "IDAT": var data = buf.ReadBytes(length); zout.Write(data, 0, data.Length); break; default: Console.WriteLine("Skipping unknown chunk \"{0}\" in PNG bitstream at offset {1}", chunk, (buf.Position - 8).ToString("X")); buf.Position += (length > buf.Available) ? buf.Available : length; break; } int crc32 = buf.ReadInt32(); } if (depth == 8) { if (colorType == PNGColorType.TruecolorWithAlpha) { //var pd = new byte[width * height * 4]; var pd = new byte[pixelStream.Length]; pixelStream.Position = 0; pixelStream.Read(pd, 0, pd.Length); ColorRGB32[] pix = new ColorRGB32[width * height]; ColorRGB32 p = new ColorRGB32(); //File.WriteAllBytes("dump.bin", pd); for (int i = 0, n = 0; i < pix.Length; i++) { if (i % width == 0) { n++; } p.Red = pd[n++]; p.Green = pd[n++]; p.Blue = pd[n++]; p.Alpha = pd[n++]; pix[i] = p; } result.Video[0] = new BitmapRGB32(width, height, pix); } else if (colorType == PNGColorType.Truecolor) { //var pd = new byte[width * height * 3]; var pd = new byte[pixelStream.Length]; pixelStream.Position = 0; pixelStream.Read(pd, 0, pd.Length); ColorRGB24[] pix = new ColorRGB24[width * height]; ColorRGB24 p = new ColorRGB24(); //File.WriteAllBytes("dump.bin", pd); for (int i = 0, n = 0; i < pix.Length; i++) { if (i % width == 0) { n++; } p.Red = pd[n++]; p.Green = pd[n++]; p.Blue = pd[n++]; pix[i] = p; } result.Video[0] = new BitmapRGB24(width, height, pix); } else { throw new NotImplementedException(); } } else { throw new NotImplementedException(); } } }
private void DecodeBitmap() { var dc = this.context; if (dc.Stage < TGADecodeStage.FooterDecoded) this.DecodeFooter(dc); var header = dc.Header; // Syntax sugar int w = dc.Header.Width; int h = dc.Header.Height; if (w < 1 || h < 1) throw new NotImplementedException(); if (header.BitsPerPixel % 8 != 0) throw new NotImplementedException("BitsPerPixel not multiple of 8"); // Number of bytes per scanline int stride = header.Width * (header.BitsPerPixel / 8); // Read all the bytes that contain pixel data var data = new byte[dc.PixelDataLength]; this.Bitstream.Seek(dc.PixelDataOffset, SeekOrigin.Begin); this.Bitstream.Read(data, 0, data.Length); if (header.ColorMapType == TGAColorMapType.ColorMapped) // Read color map data throw new NotImplementedException(); else if (header.ImageType == TGAImageType.UncompressedTrueColor) { if (header.BitsPerPixel == 16) throw new NotImplementedException(); // TODO: Implement support for 16-bit TGA decoding. else if (header.BitsPerPixel == 24) { // Create an array of all the pixels in the bitmap (width x height). var pixels = new ColorRGB24[w * h]; // ...and assign it to the Bitmap that will eventually be returned. dc.DecodedBitmap = new BitmapRGB24(w, h, pixels); var n = -1; if (dc.PixelOrder == TGAPixelOrder.BottomLeft) { var line = new ColorRGB24[w]; for (int y = h; y > 0; --y) { for (int x = 0; x < line.Length; ++x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; } line.CopyTo(pixels, (y - 1) * line.Length); } } else if (dc.PixelOrder == TGAPixelOrder.BottomRight) { var line = new ColorRGB24[w]; // BTT + Right-to-Left (RTL) pixel order. for (int y = h; y > 0; --y) { // Iterate over the pixels in the scanline from right-to-left. for (int x = line.Length - 1; x >= 0; --x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; } line.CopyTo(pixels, (y - 1) * line.Length); } } else if (dc.PixelOrder == TGAPixelOrder.TopLeft) { // Top-to-bottom (TTB) + LTR pixel order. for (int i = 0; i < pixels.Length; i++) { // All pixels can be decoded in one pass; TTB + LTR is the way bitmaps are laid out in memory. pixels[i].Blue = data[++n]; pixels[i].Green = data[++n]; pixels[i].Red = data[++n]; } } else if (dc.PixelOrder == TGAPixelOrder.TopRight) { var line = new ColorRGB24[w]; for (int y = 0; y < h; ++y) { for (int x = line.Length - 1; x >= 0; --x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; } line.CopyTo(pixels, y * line.Length); } } else throw new NotImplementedException(); } else if (header.BitsPerPixel == 32) // Same as above, plus alpha channel. { // Create an array of all the pixels in the bitmap (width x height). var pixels = new ColorRGB32[w * h]; // ...and assign it to the Bitmap that will eventually be returned. dc.DecodedBitmap = new BitmapRGB32(w, h, pixels); int n = -1; var line = new ColorRGB32[w]; // Most common scanline direction first; TGA stores scanlines bottom-to-top by default. if (dc.PixelOrder == TGAPixelOrder.BottomLeft) { // Bottom-to-top (BTT) + Left-to-right (LTR) pixel order. for (int y = h; y > 0; --y) { for (int x = 0; x < line.Length; ++x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; line[x].Alpha = data[++n]; } line.CopyTo(pixels, (y - 1) * line.Length); } } else if (dc.PixelOrder == TGAPixelOrder.BottomRight) { for (int y = h; y > 0; --y) { // Iterate over the pixels in the scanline from right-to-left. for (int x = line.Length - 1; x >= 0; --x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; line[x].Alpha = data[++n]; } line.CopyTo(pixels, (y - 1) * line.Length); } } else if (dc.PixelOrder == TGAPixelOrder.TopLeft) { for (int i = 0; i < pixels.Length; ++i) { // All pixels can be decoded in one pass; TTB + LTR is the way bitmaps are laid out in memory. pixels[i].Blue = data[++n]; pixels[i].Green = data[++n]; pixels[i].Red = data[++n]; pixels[i].Alpha = data[++n]; } } else if (dc.PixelOrder == TGAPixelOrder.TopRight) { for (int y = 0; y < h; ++y) { for (int x = line.Length - 1; x >= 0; --x) { line[x].Blue = data[++n]; line[x].Green = data[++n]; line[x].Red = data[++n]; line[x].Alpha = data[++n]; } line.CopyTo(pixels, y * line.Length); } } } } else if (header.ImageType == TGAImageType.RunLengthEncodedTrueColor) { int n = -1; bool raw = false; byte p; if (header.BitsPerPixel == 16) { throw new NotImplementedException(); } if (header.BitsPerPixel == 24) { // Create an array of all the pixels in the bitmap (width x height). var pixels = new ColorRGB24[w * h]; // ...and assign it to the Bitmap that will eventually be returned. dc.DecodedBitmap = new BitmapRGB24(w, h, pixels); ColorRGB24 px = new ColorRGB24(); // Operate on a line-by-line basis; RLE packets will never wrap from one scanline to another. var line = new ColorRGB24[w]; // Most common scanline direction first; TGA stores scanlines bottom-to-top by default. if (dc.PixelOrder == TGAPixelOrder.BottomLeft) { for (int y = h; y > 0; --y) { for (int x = 0, e = 0; x < line.Length; ++x, --e) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } line[x] = px; } line.CopyTo(pixels, (y - 1) * w); } } else if (dc.PixelOrder == TGAPixelOrder.BottomRight) { for (int y = h; y > 0; --y) { for (int x = w, e = 0; x >= 0; --x, --e) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } line[x] = px; } line.CopyTo(pixels, (y - 1) * w); } } else if (dc.PixelOrder == TGAPixelOrder.TopLeft) { for (int i = 0, e = 0; i < pixels.Length; ++i) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } pixels[i] = px; } } else if (dc.PixelOrder == TGAPixelOrder.TopRight) { throw new NotImplementedException(); /* for (int y = 0; y < h; y++) { for (int x = w - 1; x >= 0; x--) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; } line[x] = px; } }*/ } } else if (header.BitsPerPixel == 32) // Just like above, but with an alpha channel. { // Create an array of all the pixels in the bitmap (width x height). var pixels = new ColorRGB32[w * h]; // ...and assign it to the Bitmap that will eventually be returned. dc.DecodedBitmap = new BitmapRGB32(w, h, pixels); ColorRGB32 px = new ColorRGB32(); // Operate on a line-by-line basis; RLE packets will never wrap from one scanline to another. var line = new ColorRGB32[w]; var len = line.Length; if (dc.PixelOrder == TGAPixelOrder.BottomLeft) { for (int y = h; y > 0; --y) { for (int x = 0, e = 0; x < len; ++x, --e) { if (e == 0) { // Read the "packet header" p = data[++n]; // Highest bit of packet header indicates RLE (1) or RAW (0). raw = (p & 0x80) != 0x80; // Remaining 7 bits indicate RLE packet length. e = 1 + (p & 0x7F); // Read color px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; px.Alpha = data[++n]; } else if (raw) { px.Blue = data[++n]; px.Green = data[++n]; px.Red = data[++n]; px.Alpha = data[++n]; } line[x] = px; } line.CopyTo(pixels, (y - 1) * w); } } else if (dc.PixelOrder == TGAPixelOrder.BottomRight) { throw new NotImplementedException(); } else if (dc.PixelOrder == TGAPixelOrder.TopLeft) { throw new NotImplementedException(); } else if (dc.PixelOrder == TGAPixelOrder.TopRight) { throw new NotImplementedException(); } } else throw new NotImplementedException(); } dc.Stage = TGADecodeStage.BitmapDecoded; }