}                            // Important colors = 0

        /// <summary>
        ///
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static BmpInfoHeader FillFromStream(Stream stream)
        {
            byte[]        buffer = new byte[_SIZE];
            BmpInfoHeader header = new BmpInfoHeader();

            stream.Read(buffer, 0, _SIZE);

            // Fill
            header.HeaderSize   = BitConverter.ToInt32(buffer, 0);
            header.Width        = BitConverter.ToInt32(buffer, 4);
            header.Height       = BitConverter.ToInt32(buffer, 8);
            header.BitsPerPixel = BitConverter.ToInt16(buffer, 14);
            header.Compression  = BitConverter.ToInt32(buffer, 16);
            header.ImageSize    = BitConverter.ToInt32(buffer, 20);
            header.ColorCount   = BitConverter.ToInt32(buffer, 32);

            // Fix for no ImageSize in the header
            if (header.ImageSize == 0)
            {
                int rowSize  = 4 * (int)Math.Ceiling((double)header.Width * (header.BitsPerPixel / 32));
                int fileSize = header.HeaderSize + (4 * (int)Math.Pow(2, header.BitsPerPixel)) + rowSize + header.Height;

                header.ImageSize = (int)fileSize;
            }

            if (header.ColorCount == 0)
            {
                header.ColorCount = (1 << header.BitsPerPixel);
            }

            // Return results
            return(header);
        }
        public int NA4 { get; set; } // Important colors = 0

        /// <summary>
        /// 
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static BmpInfoHeader FillFromStream(Stream stream)
        {
            byte[] buffer = new byte[_SIZE];
            BmpInfoHeader header = new BmpInfoHeader();

            stream.Read(buffer, 0, _SIZE);

            // Fill
            header.HeaderSize = BitConverter.ToInt32(buffer, 0);
            header.Width = BitConverter.ToInt32(buffer, 4);
            header.Height = BitConverter.ToInt32(buffer, 8);
            header.BitsPerPixel = BitConverter.ToInt16(buffer, 14);
            header.Compression = BitConverter.ToInt32(buffer, 16);
            header.ImageSize = BitConverter.ToInt32(buffer, 20);
            header.ColorCount = BitConverter.ToInt32(buffer, 32);

            // Fix for no ImageSize in the header
            if (header.ImageSize == 0)
            {
                int rowSize = 4 * (int)Math.Ceiling((double)header.Width * (header.BitsPerPixel / 32));
                int fileSize = header.HeaderSize + (4 * (int)Math.Pow(2, header.BitsPerPixel)) + rowSize + header.Height;

                header.ImageSize = (int)fileSize;
            }

            if (header.ColorCount == 0)
            {
                header.ColorCount = (1 << header.BitsPerPixel);
            }

            // Return results
            return header;
        }
        private static EditableImage Read4BitBmp(byte[] buffer, Color[] palette, BmpInfoHeader header)
        {
            int   width     = (header.Width + 1) / 2;
            int   alignment = width % 4;     // Rows are aligned on 4 byte boundaries
            int   rowbase   = 0;
            int   colbase   = 0;
            int   offset;
            int   realRow;
            Color color1;
            Color color2;

            EditableImage image = new EditableImage(header.Width, header.Height);

            if (alignment != 0)
            {
                alignment = 4 - alignment;                        // Calculate row padding
            }

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * (width + alignment));
                for (int col = 0; col < width; col++)
                {
                    colbase = col * 2;
                    offset  = rowbase + col;
                    realRow = header.Height - row - 1;          // Reverse row
                    color1  = palette[(buffer[offset]) >> 4];
                    color2  = palette[(buffer[offset]) & 0x0F];
                    image.SetPixel(colbase, realRow, color1.R, color1.G, color1.B, 255);
                    image.SetPixel(colbase + 1, realRow, color2.R, color2.G, color2.B, 255);
                }
            }

            return(image);
        }
        private static EditableImage Read24BitBmp(byte[] buffer, BmpInfoHeader header)
        {
            int alignment = (header.Width * 3) % 4;       // Rows are aligned on 4 byte boundaries
            int rowbase   = 0;
            int offset;
            int realRow;

            EditableImage image = new EditableImage(header.Width, header.Height);

            if (alignment != 0)
            {
                alignment = 4 - alignment;                        // Calculate row padding
            }

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * ((header.Width * 3) + alignment));
                for (int col = 0; col < header.Width; col++)
                {
                    offset  = rowbase + (col * 3);
                    realRow = header.Height - row - 1;          // Reverse row
                    if (offset >= buffer.Length)
                    {
#if SILVERLIGHT
                        HtmlPage.Window.Alert("Error - outside of bounds and not sure why");
#else
                        throw new Exception("Error - outside of bounds and not sure why");
#endif
                    }
                    image.SetPixel(col, realRow, buffer[offset + 2], buffer[offset + 1], buffer[offset], 255);
                }
            }

            return(image);
        }
        private static EditableImage Read8BitBmp(byte[] buffer, Color[] palette, BmpInfoHeader header)
        {
            int   alignment = header.Width % 4;     // Rows are aligned on 4 byte boundaries
            int   rowbase   = 0;
            int   offset;
            int   realRow;
            Color color;

            EditableImage image = new EditableImage(header.Width, header.Height);

            if (alignment != 0)
            {
                alignment = 4 - alignment;                        // Calculate row padding
            }

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * (header.Width + alignment));
                for (int col = 0; col < header.Width; col++)
                {
                    offset  = rowbase + col;
                    realRow = header.Height - row - 1;          // Reverse row
                    color   = palette[buffer[offset]];
                    image.SetPixel(col, realRow, color.R, color.G, color.B, color.A);
                }
            }

            return(image);
        }
        private static EditableImage Read565Bmp(byte[] buffer, BmpInfoHeader header)
        {
            int   rowbase = 0;
            int   offset;
            int   realRow;
            short color;
            byte  red;
            byte  green;
            byte  blue;
            int   scaleR = 256 / 32;
            int   scaleG = 256 / 64;

            EditableImage image = new EditableImage(header.Width, header.Height);

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * header.Width * 2);
                for (int col = 0; col < header.Width; col++)
                {
                    offset  = rowbase + (col * 2);
                    realRow = header.Height - row - 1;          // Reverse row

                    // Get color and convert
                    color = BitConverter.ToInt16(buffer, offset);
                    red   = (byte)(((color & _REDMASK) >> 11) * scaleR);
                    green = (byte)(((color & _GREENMASK) >> 5) * scaleG);
                    blue  = (byte)(((color & _BLUEMASK)) * scaleR);

                    // Set pixel
                    image.SetPixel(col, realRow, red, green, blue, 255);
                }
            }

            return(image);
        }
        private static EditableImage ReadPaletteBmp(byte[] buffer, Color[] palette, BmpInfoHeader header, int bpp)
        {
            int   ppb       = 8 / bpp;             // Pixels per byte (bits per pixel)
            int   width     = (header.Width + ppb - 1) / ppb;
            int   alignment = width % 4;           // Rows are aligned on 4 byte boundaries
            int   mask      = (0xFF >> (8 - bpp)); // Bit mask
            int   rowbase;
            int   colbase;
            int   offset;
            int   realRow;
            Color color;

            EditableImage image = new EditableImage(header.Width, header.Height);

            if (alignment != 0)
            {
                alignment = 4 - alignment;                        // Calculate row padding
            }

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * (width + alignment));
                for (int col = 0; col < width; col++)
                {
                    offset  = rowbase + col;
                    colbase = col * ppb;
                    realRow = header.Height - row - 1;                  // Reverse row
                    for (int shift = 0; ((shift < ppb) && ((colbase + shift) < header.Width)); shift++)
                    {
                        color = palette[((buffer[offset]) >> (8 - bpp - (shift * bpp))) & mask];
                        image.SetPixel(colbase + shift, realRow, color.R, color.G, color.B, 255);
                    }
                }
            }

            return(image);
        }
        /// <summary>
        /// Decodes a bitmap stream into an editable image.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static EditableImage Decode(Stream stream)
        {
            EditableImage image = null;

            // See http://en.wikipedia.org/wiki/BMP_file_format

            try
            {
                byte[]        buffer;
                BmpFileHeader fHeader;
                BmpInfoHeader iHeader;

                // Read File Header
                fHeader = BmpFileHeader.FillFromStream(stream);

                // Validate file type
                if (fHeader.BitmapType != 19778)
                {
                    throw new Exception("Invalid BMP file");
                }

                // Read Info Header
                iHeader = BmpInfoHeader.FillFromStream(stream);

                // Data
                if ((iHeader.Compression == 0) && (iHeader.BitsPerPixel == 24))
                {
                    // Read bits into the buffer
                    buffer = new byte[iHeader.ImageSize];
                    stream.Read(buffer, 0, iHeader.ImageSize);

                    // Standard RGB file
                    image = Read24BitBmp(buffer, iHeader);
                }
                else if ((iHeader.Compression == 0) && (iHeader.BitsPerPixel <= 8))
                {
                    int     count = iHeader.ColorCount * 4;   // 4 bytes per color
                    Color[] palette;

                    // Read colors
                    buffer = new byte[count];
                    stream.Read(buffer, 0, count);

                    palette = FillColorPalette(buffer, iHeader.ColorCount);

                    // Read data
                    buffer = new byte[iHeader.ImageSize];
                    stream.Read(buffer, 0, iHeader.ImageSize);

                    image = ReadPaletteBmp(buffer, palette, iHeader, iHeader.BitsPerPixel);
                }
                else if ((iHeader.Compression == 3) && (iHeader.BitsPerPixel == 16))
                {
                    // Special 565 16 bit encoding - see http://www.virtualdub.org/blog/pivot/entry.php?id=177
                    int remainder = fHeader.OffsetToData - (int)stream.Position;
                    int rMask;
                    int bMask;
                    int gMask;

                    // Read remainder
                    buffer = new byte[remainder];
                    stream.Read(buffer, 0, remainder);

                    // Read masks
                    rMask = BitConverter.ToInt32(buffer, 0);
                    gMask = BitConverter.ToInt32(buffer, 4);
                    bMask = BitConverter.ToInt32(buffer, 8);

                    if ((_REDMASK != rMask) || (_GREENMASK != gMask) || (_BLUEMASK != bMask))
                    {
                        // Not 565 format
                        throw new Exception("Unsupported 16 bit format: " + rMask.ToString("X2") + ", " + bMask.ToString("X2") + ", " + gMask.ToString("X2"));
                    }

                    // Read data
                    remainder = iHeader.Height * iHeader.Width * 2;     // 2 bytes per pixel
                    buffer    = new byte[remainder];
                    stream.Read(buffer, 0, remainder);

                    // Convert to an image
                    image = Read565Bmp(buffer, iHeader);
                }
                else
                {
                    throw new Exception("Unsupported format (compression: " + iHeader.Compression.ToString() + ", Bits per pixel: " + iHeader.BitsPerPixel.ToString() + ")");
                }
            }
            catch (Exception ex)
            {
#if SILVERLIGHT
                HtmlPage.Window.Alert("Error parsing BMP file: " + ex.Message);
#else
                throw;
#endif
            }

            return(image);
        }
        private static EditableImage Read24BitBmp(byte[] buffer, BmpInfoHeader header)
        {
            int alignment = (header.Width * 3) % 4;       // Rows are aligned on 4 byte boundaries
            int rowbase = 0;
            int offset;
            int realRow;

            EditableImage image = new EditableImage(header.Width, header.Height);

            if (alignment != 0)
            {
                alignment = 4 - alignment;                        // Calculate row padding
            }

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * ((header.Width * 3) + alignment));
                for (int col = 0; col < header.Width; col++)
                {
                    offset = rowbase + (col * 3);
                    realRow = header.Height - row - 1;          // Reverse row
                    if (offset >= buffer.Length)
                    {
#if SILVERLIGHT
                        HtmlPage.Window.Alert("Error - outside of bounds and not sure why");
#else
                        throw new Exception("Error - outside of bounds and not sure why");
#endif
                    }
                    image.SetPixel(col, realRow, buffer[offset + 2], buffer[offset + 1], buffer[offset], 255);
                }
            }

            return image;
        }
        private static EditableImage Read8BitBmp(byte[] buffer, Color[] palette, BmpInfoHeader header)
        {
            int alignment = header.Width % 4;       // Rows are aligned on 4 byte boundaries
            int rowbase = 0;
            int offset;
            int realRow;
            Color color;

            EditableImage image = new EditableImage(header.Width, header.Height);

            if (alignment != 0)
            {
                alignment = 4 - alignment;                        // Calculate row padding
            }

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * (header.Width + alignment));
                for (int col = 0; col < header.Width; col++)
                {
                    offset = rowbase + col;
                    realRow = header.Height - row - 1;          // Reverse row
                    color = palette[buffer[offset]];
                    image.SetPixel(col, realRow, color.R, color.G, color.B, color.A);
                }
            }

            return image;
        }
        private static EditableImage Read4BitBmp(byte[] buffer, Color[] palette, BmpInfoHeader header)
        {
            int width = (header.Width + 1) / 2;
            int alignment = width % 4;       // Rows are aligned on 4 byte boundaries
            int rowbase = 0;
            int colbase = 0;
            int offset;
            int realRow;
            Color color1;
            Color color2;

            EditableImage image = new EditableImage(header.Width, header.Height);

            if (alignment != 0)
            {
                alignment = 4 - alignment;                        // Calculate row padding
            }

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * (width + alignment));
                for (int col = 0; col < width; col++)
                {
                    colbase = col * 2;
                    offset = rowbase + col;
                    realRow = header.Height - row - 1;          // Reverse row
                    color1 = palette[(buffer[offset]) >> 4];
                    color2 = palette[(buffer[offset]) & 0x0F];
                    image.SetPixel(colbase, realRow, color1.R, color1.G, color1.B, 255);
                    image.SetPixel(colbase + 1, realRow, color2.R, color2.G, color2.B, 255);
                }
            }

            return image;
        }
        private static EditableImage ReadPaletteBmp(byte[] buffer, Color[] palette, BmpInfoHeader header, int bpp)
        {
            int ppb = 8 / bpp;                    // Pixels per byte (bits per pixel)
            int width = (header.Width + ppb - 1) / ppb;
            int alignment = width % 4;          // Rows are aligned on 4 byte boundaries
            int mask = (0xFF >> (8 - bpp));       // Bit mask
            int rowbase;
            int colbase;
            int offset;
            int realRow;
            Color color;

            EditableImage image = new EditableImage(header.Width, header.Height);

            if (alignment != 0)
            {
                alignment = 4 - alignment;                        // Calculate row padding
            }

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * (width + alignment));
                for (int col = 0; col < width; col++)
                {
                    offset = rowbase + col;
                    colbase = col * ppb;
                    realRow = header.Height - row - 1;                  // Reverse row
                    for (int shift = 0; ((shift < ppb) && ((colbase + shift) < header.Width)); shift++)
                    {
                        color = palette[((buffer[offset]) >> (8 - bpp - (shift * bpp))) & mask];
                        image.SetPixel(colbase + shift, realRow, color.R, color.G, color.B, 255);
                    }
                }
            }

            return image;
        }
        private static EditableImage Read565Bmp(byte[] buffer, BmpInfoHeader header)
        {
            int rowbase = 0;
            int offset;
            int realRow;
            short color;
            byte red;
            byte green;
            byte blue;
            int scaleR = 256 / 32;
            int scaleG = 256 / 64;

            EditableImage image = new EditableImage(header.Width, header.Height);

            for (int row = 0; row < header.Height; row++)
            {
                rowbase = (row * header.Width * 2);
                for (int col = 0; col < header.Width; col++)
                {
                    offset = rowbase + (col * 2);
                    realRow = header.Height - row - 1;          // Reverse row

                    // Get color and convert
                    color = BitConverter.ToInt16(buffer, offset);
                    red = (byte)(((color & _REDMASK) >> 11) * scaleR);
                    green = (byte)(((color & _GREENMASK) >> 5) * scaleG);
                    blue = (byte)(((color & _BLUEMASK)) * scaleR);

                    // Set pixel
                    image.SetPixel(col, realRow, red, green, blue, 255);
                }
            }

            return image;
        }