public void ColorRGB24_Accessor() { byte r = (byte)NextComponent(byte.MaxValue); byte g = (byte)NextComponent(byte.MaxValue); byte b = (byte)NextComponent(byte.MaxValue); ColorRGB24 v = new ColorRGB24(r, g, b); float c; Assert.DoesNotThrow(() => c = v[0]); Assert.DoesNotThrow(() => c = v[1]); Assert.DoesNotThrow(() => c = v[2]); Assert.Throws <IndexOutOfRangeException>(() => c = v[+3]); Assert.Throws <IndexOutOfRangeException>(() => c = v[-1]); Assert.DoesNotThrow(() => v[0] = 1.0f); Assert.DoesNotThrow(() => v[1] = 1.0f); Assert.DoesNotThrow(() => v[2] = 1.0f); Assert.Throws <IndexOutOfRangeException>(() => v[+3] = 0.0f); Assert.Throws <IndexOutOfRangeException>(() => v[-1] = 0.0f); Assert.DoesNotThrow(() => v[2] = 0.0f); Assert.DoesNotThrow(() => v[2] = 1.0f); Assert.Throws <InvalidOperationException>(() => v[2] = -1.0f); Assert.Throws <InvalidOperationException>(() => v[2] = +1.1f); }
public void ColorRGB24_CastFromColor() { const double Epsilon = 0.25; Random random = new Random(); double r = NextComponent(random, 1.0); double g = NextComponent(random, 1.0); double b = NextComponent(random, 1.0); Color c = Color.FromArgb(byte.MaxValue, (int)(r * byte.MaxValue), (int)(g * byte.MaxValue), (int)(b * byte.MaxValue)); ColorRGB24 v = (ColorRGB24)c; Assert.AreEqual((float)r, v[0], Epsilon); Assert.AreEqual((float)g, v[1], Epsilon); Assert.AreEqual((float)b, v[2], Epsilon); // Not influenced by alpha c = Color.FromArgb(0, (int)(r * byte.MaxValue), (int)(g * byte.MaxValue), (int)(b * byte.MaxValue)); v = (ColorRGB24)c; Assert.AreEqual((float)r, v[0], Epsilon); Assert.AreEqual((float)g, v[1], Epsilon); Assert.AreEqual((float)b, v[2], Epsilon); }
public void ColorRGB24_CastToRGBA() { byte r = (byte)NextComponent(byte.MaxValue); byte g = (byte)NextComponent(byte.MaxValue); byte b = (byte)NextComponent(byte.MaxValue); ColorRGB24 v = new ColorRGB24(r, g, b); ColorRGBA32 vRGBA = v; }
public void ColorRGB24_PixelType() { byte r = (byte)NextComponent(byte.MaxValue); byte g = (byte)NextComponent(byte.MaxValue); byte b = (byte)NextComponent(byte.MaxValue); ColorRGB24 v = new ColorRGB24(r, g, b); Assert.AreNotEqual(PixelLayout.None, v.PixelType); }
public void ColorRGB24_TestConstructor1() { byte r = (byte)byte.MaxValue; byte g = (byte)byte.MaxValue; byte b = (byte)byte.MaxValue; ColorRGB24 v = new ColorRGB24(r, g, b); Assert.AreEqual(r, v.Red); Assert.AreEqual(g, v.Green); Assert.AreEqual(b, v.Blue); }
public void ColorRGB24_CastToVertex4() { byte r = (byte)NextComponent(byte.MaxValue); byte g = (byte)NextComponent(byte.MaxValue); byte b = (byte)NextComponent(byte.MaxValue); ColorRGB24 v = new ColorRGB24(r, g, b); Vertex3ub vArray = v; Assert.AreEqual(r, vArray.x); Assert.AreEqual(g, vArray.y); Assert.AreEqual(b, vArray.z); }
public void ColorRGB24_CastToRGBA() { byte r = (byte)NextComponent(byte.MaxValue); byte g = (byte)NextComponent(byte.MaxValue); byte b = (byte)NextComponent(byte.MaxValue); ColorRGB24 v = new ColorRGB24(r, g, b); ColorRGBA32 vRGBA = v; Assert.AreEqual(v.Red, vRGBA.Red); Assert.AreEqual(v.Green, vRGBA.Green); Assert.AreEqual(v.Blue, vRGBA.Blue); Assert.AreEqual(byte.MaxValue, vRGBA.Alpha); }
public void ColorRGB24_CastToArray() { byte r = (byte)NextComponent(byte.MaxValue); byte g = (byte)NextComponent(byte.MaxValue); byte b = (byte)NextComponent(byte.MaxValue); ColorRGB24 v = new ColorRGB24(r, g, b); byte[] vArray = v; Assert.AreEqual(3, vArray.Length); Assert.AreEqual(r, vArray[0]); Assert.AreEqual(g, vArray[1]); Assert.AreEqual(b, vArray[2]); }
private BitmapRGB24 ApplyEffectRGB24(BitmapRGB24 input) { ColorRGB24[] pix = new ColorRGB24[input.Size.Elements]; var c = this.Contrast; for (int i = 0; i < pix.Length; i++) { pix[i].Red = (byte)((pix[i].Red - 127) * c); pix[i].Green = (byte)((pix[i].Green - 127) * c); pix[i].Blue = (byte)((pix[i].Blue - 127) * c); } return(new BitmapRGB24(input.Size, pix)); }
private void BoxBlurRGB24(BitmapRGB24 input, BitmapRGB24 output, BitmapRGB32 mask = null) { Contract.Requires(input != null); Contract.Requires(output != null); Contract.Requires(input.Width == output.Width); Contract.Requires(input.Height == output.Height); int radius = this.Radius; int w = input.Width; int h = input.Height; var bmp = output; var pix = bmp.Pixels; float div = (float)Math.Pow((radius * 2 + 1), 2); for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { var tr = 0.0; var tg = 0.0; var tb = 0.0; for (int ky = -radius; ky <= radius; ky++) { for (int kx = -radius; kx <= radius; kx++) { var px = Math.Max(Math.Min(x + kx, w - 1), 0); var py = Math.Max(Math.Min(y + ky, h - 1), 0); var p = input[px, py]; tr += p.Red; tg += p.Green; tb += p.Blue; //div += 1; } } //total.Alpha = 1.0f; bmp[x, y] = new ColorRGB24((byte)(tr / 255.0 * (255.0 / div)), (byte)(tg / 255.0 * (255.0 / div)), (byte)(tb / 255.0 * (255.0 / div))); } } }
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(); } } }
public unsafe override void EncodeImage(Image image) { this.Open(); this.Bitstream.Seek(TGABitstreamHeader.Length, System.IO.SeekOrigin.Begin); var tga = image as TGAImage; if (tga == null) throw new NotImplementedException(); var header = this.context.Header; header.Width = (ushort)tga.Width; header.Height = (ushort)tga.Height; // Temporarily force RLE off until RLE is implemented properly. tga.UseRunLengthEncoding = false; var bitmap = tga.Flatten(); if (bitmap is BitmapRGB24) { header.BitsPerPixel = 24; header.AttributeBits = 0; header.ImageDescriptor = TGAImageDescriptor.BottomLeft; var bmp = bitmap as BitmapRGB24; if (tga.UseRunLengthEncoding) { throw new NotImplementedException(); header.ImageType = TGAImageType.RunLengthEncodedTrueColor; var buffer = new byte[(bmp.Size.Elements * 4)]; var pix = bmp.Pixels; int n = 0; var line = new ColorRGB24[tga.Width]; // Operate on each scanline. for (int s = tga.Height - 1; s >= 0; --s) { // Copy pixels from source image into scanline buffer. Array.Copy(pix, s * tga.Width, line, 0, line.Length); int idx = 0; int start = 0; BeginPacket: if (idx >= line.Length) goto EndLine; else { start = idx; if (line[idx] == line[idx + 1]) goto NextPixelRLE; } NextPixelRLE: if (line[idx] == line[++idx]) idx = 0; EndLine: continue; } this.Bitstream.Write(buffer, 0, ++n); } else { header.ImageType = TGAImageType.UncompressedTrueColor; var buffer = new byte[bmp.Size.Elements * 3]; var pix = bmp.Pixels; for (int i = 0, n = -1; i < pix.Length; ++i) { buffer[++n] = pix[i].Blue; buffer[++n] = pix[i].Green; buffer[++n] = pix[i].Red; } this.Bitstream.Write(buffer, 0, buffer.Length); } } else if (bitmap is BitmapRGB32) { var bmp = bitmap as BitmapRGB32; if (tga.UseRunLengthEncoding) throw new NotImplementedException(); else { header.ImageType = TGAImageType.UncompressedTrueColor; var buffer = new byte[bmp.Size.Elements * 4]; var pix = bmp.Pixels; ColorRGB32 p; for (int i = 0, n = -1; i < pix.Length; ++i) { p = pix[i]; buffer[++n] = p.Blue; buffer[++n] = p.Green; buffer[++n] = p.Red; buffer[++n] = p.Alpha; } } } else { throw new NotImplementedException(); } this.context.Header = header; this.Close(); }
public unsafe override void EncodeImage(Image image) { this.Open(); this.Bitstream.Seek(TGABitstreamHeader.Length, System.IO.SeekOrigin.Begin); var tga = image as TGAImage; if (tga == null) { throw new NotImplementedException(); } var header = this.context.Header; header.Width = (ushort)tga.Width; header.Height = (ushort)tga.Height; // Temporarily force RLE off until RLE is implemented properly. tga.UseRunLengthEncoding = false; var bitmap = tga.Flatten(); if (bitmap is BitmapRGB24) { header.BitsPerPixel = 24; header.AttributeBits = 0; header.ImageDescriptor = TGAImageDescriptor.BottomLeft; var bmp = bitmap as BitmapRGB24; if (tga.UseRunLengthEncoding) { throw new NotImplementedException(); header.ImageType = TGAImageType.RunLengthEncodedTrueColor; var buffer = new byte[(bmp.Size.Elements * 4)]; var pix = bmp.Pixels; int n = 0; var line = new ColorRGB24[tga.Width]; // Operate on each scanline. for (int s = tga.Height - 1; s >= 0; --s) { // Copy pixels from source image into scanline buffer. Array.Copy(pix, s * tga.Width, line, 0, line.Length); int idx = 0; int start = 0; BeginPacket: if (idx >= line.Length) { goto EndLine; } else { start = idx; if (line[idx] == line[idx + 1]) { goto NextPixelRLE; } } NextPixelRLE: if (line[idx] == line[++idx]) { idx = 0; } EndLine: continue; } this.Bitstream.Write(buffer, 0, ++n); } else { header.ImageType = TGAImageType.UncompressedTrueColor; var buffer = new byte[bmp.Size.Elements * 3]; var pix = bmp.Pixels; for (int i = 0, n = -1; i < pix.Length; ++i) { buffer[++n] = pix[i].Blue; buffer[++n] = pix[i].Green; buffer[++n] = pix[i].Red; } this.Bitstream.Write(buffer, 0, buffer.Length); } } else if (bitmap is BitmapRGB32) { var bmp = bitmap as BitmapRGB32; if (tga.UseRunLengthEncoding) { throw new NotImplementedException(); } else { header.ImageType = TGAImageType.UncompressedTrueColor; var buffer = new byte[bmp.Size.Elements * 4]; var pix = bmp.Pixels; ColorRGB32 p; for (int i = 0, n = -1; i < pix.Length; ++i) { p = pix[i]; buffer[++n] = p.Blue; buffer[++n] = p.Green; buffer[++n] = p.Red; buffer[++n] = p.Alpha; } } } else { throw new NotImplementedException(); } this.context.Header = header; this.Close(); }
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; }