示例#1
0
        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);
        }
示例#2
0
        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();
                }
            }
        }
示例#3
0
        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;
        }
示例#4
0
        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();
                }
            }
        }
示例#5
0
        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;
        }