Example #1
0
        public List <WADImagePixel> GetPaletteColors()
        {
            if (Palette == null || Palette.Length < 512)
            {
                return(null);
            }
            var list = new List <WADImagePixel>();

            for (int i = 0; i < 512; i += 2)
            {
                var pix = new WADImagePixel();
                pix.Color[0] = Palette[i];
                pix.Color[1] = Palette[i + 1];
                list.Add(pix);
            }
            return(list);
        }
Example #2
0
        public BMP(byte[] data, int index = 0)
        {
            // Header is 64 byte
            if (data.Length < (index + 64))
            {
                Trace.WriteLine("BMP: Data is not BMP Image. Not enough bytes to read header");
                throw new InvalidOperationException("Not enough bytes to read header!");
            }

            int    start      = index + 32;
            UInt64 dataSize64 =
                (UInt64)data[start++] |
                (UInt64)data[start++] << 8 |
                    (UInt64)data[start++] << 16 |
                    (UInt64)data[start++] << 24 |
                    (UInt64)data[start++] << 32 |
                    (UInt64)data[start++] << 40 |
                    (UInt64)data[start++] << 48 |
                    (UInt64)data[start++] << 56;

            if (dataSize64 > Int32.MaxValue)
            {
                Trace.WriteLine("BMP: Data size is too large to handle");
                throw new InvalidOperationException("Data size is too large to handle!");
            }
            int dataSize = (int)dataSize64;

            // Unsure if Flag is really used for file format
            // Using name instead
            // -----------------------------------------------
            // Check BMP Flag
            Name = Encoding.ASCII.GetString(data, index, 32).TrimEnd('\0');
            //if (data[start] == 0x03) // !!! TODO danger !!! Should be 0
            if (!Name.EndsWith("BMP"))
            {
                Trace.WriteLine("BMP: Not a BMP");
                throw new InvalidOperationException("Not a BMP!");
            }
            // -----------------------------------------------

            // Check color depth
            start = index + 32 + 8 + 8 + 8;
            if (data[start] != 8 && data[start + 1] != 0)
            {
                Trace.WriteLine("BMP: " + Name + ": Color depth flag is not set to 8");
                throw new InvalidOperationException(Name + ": Color depth flag is not set to 8!");
            }

            // Full Data Size:
            // + 64 byte Header
            // + dataSize Pixel Data
            // + 4 Byte Color Palette ID

            UInt64 requiredSize64 = 64 + dataSize64 + 4;

            if (requiredSize64 > Int32.MaxValue)
            {
                Trace.WriteLine("BMP: " + Name + ": Data size is too large to handle");
                throw new InvalidOperationException(Name + ": Data size is too large to handle!");
            }
            int requiredSize = (int)requiredSize64;

            if (data.Length < (index + requiredSize))
            {
                Trace.WriteLine("BMP: " + Name + ": Data is not BMP Image. Not enough bytes for data");
                throw new InvalidOperationException(Name + ": Not enough bytes for data!");
            }
            // =====================================================================
            // RAW Data is available
            // =====================================================================
            _rawData = new byte[requiredSize];
            Array.Copy(data, index, _rawData, 0, requiredSize);

            start  = 32 + 8 + 8;
            Height =
                (UInt32)_rawData[start++] |
                (UInt32)_rawData[start++] << 8 |
                    (UInt32)_rawData[start++] << 16 |
                    (UInt32)_rawData[start++] << 24;
            Width =
                (UInt32)_rawData[start++] |
                (UInt32)_rawData[start++] << 8 |
                    (UInt32)_rawData[start++] << 16 |
                    (UInt32)_rawData[start++] << 24;

            start             = 64 + dataSize;
            ColorPaletteIndex =
                (UInt32)_rawData[start++] |
                (UInt32)_rawData[start++] << 8 |
                    (UInt32)_rawData[start++] << 16 |
                    (UInt32)_rawData[start++] << 24;

            // Read the pixels

            // Check if last byte of data and third byte are the same
            if (_rawData[64 + 3 - 1] != _rawData[64 + dataSize - 1])
            {
                throw new InvalidOperationException("BMP: " + Name + ": Pixel data invalid. The third byte is not repeated at the end.");
            }

            //for (int i = 64; i < 64 + dataSize; ++i)
            //{
            //    if ((i - 64) % (Width + 2) == 0) Debug.Write("\n");
            //    Debug.Write(string.Format("{0:X2} ", _rawData[i]));
            //}
            //Debug.Write("\n");

            var pixels       = new WADImagePixel[Width * Height];
            int max          = 64 + dataSize;
            int currentPixel = 0;

            for (int i = 64; i < max - 1; ++i) // last value was already checked
            {
                int lineIndex = (i - 64) % ((int)Width + 2);
                if (i > 64 && lineIndex == Width)
                {
                    // Reached end of line
                    // The first two bytes will be repeated
                    if (_rawData[i] != _rawData[i - Width])
                    {
                        throw new InvalidOperationException("BMP: " + Name + ": Pixel data invalid. First byte of line not repeated at the end.");
                    }
                    ++i;
                    if (_rawData[i] != _rawData[i - Width])
                    {
                        throw new InvalidOperationException("BMP: " + Name + ": Pixel data invalid. Second byte of line not repeated at the end.");
                    }
                    ++i;
                }
                if (i < max - 1 && currentPixel >= pixels.Length)
                {
                    throw new InvalidOperationException("BMP: There is too much pixel data.");
                }
                if (i >= max - 1)
                {
                    break;
                }
                pixels[currentPixel++] = new WADImagePixel()
                {
                    Opacity = 255, PaletteValue = _rawData[i]
                };
            }

            Pixels       = new WADImagePixel[Height, Width];
            currentPixel = 0;
            for (int h = 0; h < Height; ++h)
            {
                for (int w = 0; w < Width; ++w)
                {
                    Pixels[h, w] = pixels[currentPixel++];
                }
            }
        }
Example #3
0
        /// <summary>
        /// Read an RLE image from an array of data.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="index"></param>
        /// <exception cref="InvalidOperationException">Thrown if data is invalid.</exception>
        public RLE(byte[] data, int index = 0)
        {
            // Header is 64 byte
            if (data.Length < (index + 64))
            {
                Trace.WriteLine("RLE: Data is not RLE Image. Not enough bytes to read header");
                throw new InvalidOperationException("Not enough bytes to read header!");
            }

            int    start      = index + 32;
            UInt64 dataSize64 =
                (UInt64)data[start++] |
                (UInt64)data[start++] << 8 |
                    (UInt64)data[start++] << 16 |
                    (UInt64)data[start++] << 24 |
                    (UInt64)data[start++] << 32 |
                    (UInt64)data[start++] << 40 |
                    (UInt64)data[start++] << 48 |
                    (UInt64)data[start++] << 56;

            if (dataSize64 > Int32.MaxValue)
            {
                Trace.WriteLine("RLE: Data size is too large to handle");
                throw new InvalidOperationException("Data size is too large to handle!");
            }
            int dataSize = (int)dataSize64;

            // Unsure if Flag is really used for file format
            // Using name instead
            // -----------------------------------------------
            // Check RLE Flag
            Name = Encoding.ASCII.GetString(data, index, 32).TrimEnd('\0');
            //if (data[start] != 3)
            if (!Name.EndsWith("RLE"))
            {
                Trace.WriteLine("RLE: " + Name + ": Not a RLE");
                throw new InvalidOperationException("" + Name + ": Not a RLE!");
            }
            // -----------------------------------------------

            // Check color depth
            start = index + 32 + 8 + 8 + 8;
            if (data[start] != 8 && data[start + 1] != 0)
            {
                Trace.WriteLine("RLE: Color depth flag is not set to 8");
                throw new InvalidOperationException("Color depth flag is not set to 8!");
            }

            // Full Data Size:
            // + 64 byte Header
            // + dataSize Pixel Data
            // + 4*4 Line Offsets Header
            // + Height*4 Line Offsets Data
            // + 4 Byte Color Palette ID

            start  = index + 32 + 8 + 8;
            Height =
                (UInt32)data[start++] |
                (UInt32)data[start++] << 8 |
                    (UInt32)data[start++] << 16 |
                    (UInt32)data[start++] << 24;

            UInt64 requiredSize64 = 64 + dataSize64 + 4 * 4 + 4 * Height + 4;

            if (requiredSize64 > Int32.MaxValue)
            {
                Trace.WriteLine("RLE: " + Name + ": Data size is too large to handle");
                throw new InvalidOperationException(Name + ": Data size is too large to handle!");
            }
            int requiredSize = (int)requiredSize64;

            if (data.Length < (index + requiredSize))
            {
                Trace.WriteLine("RLE: " + Name + ": Data is not RLE Image. Not enough bytes for data");
                throw new InvalidOperationException(Name + ": Not enough bytes for data!");
            }
            // =====================================================================
            // RAW Data is available
            // =====================================================================
            _rawData = new byte[requiredSize];
            Array.Copy(data, index, _rawData, 0, requiredSize);
            start = 32 + 8 + 8 + 4;
            Width =
                (UInt32)_rawData[start++] |
                (UInt32)_rawData[start++] << 8 |
                    (UInt32)_rawData[start++] << 16 |
                    (UInt32)_rawData[start++] << 24;
            //Name = Encoding.ASCII.GetString(_rawData, 0, 32).TrimEnd('\0');

            // Offset Data
            start = 64 + dataSize;
            UInt32 offsetDataSize =
                (UInt32)_rawData[start++] |
                (UInt32)_rawData[start++] << 8 |
                    (UInt32)_rawData[start++] << 16 |
                    (UInt32)_rawData[start++] << 24;
            string offsetName = Encoding.ASCII.GetString(data, (int)start, 4).TrimEnd('\0');

            start += 4;
            UInt32 offsetWidth =
                (UInt32)_rawData[start++] |
                (UInt32)_rawData[start++] << 8 |
                    (UInt32)_rawData[start++] << 16 |
                    (UInt32)_rawData[start++] << 24;
            UInt32 offsetHeight =
                (UInt32)_rawData[start++] |
                (UInt32)_rawData[start++] << 8 |
                    (UInt32)_rawData[start++] << 16 |
                    (UInt32)_rawData[start++] << 24;

            if (offsetDataSize != Height * 4 + 12)
            {
                Trace.WriteLine("RLE: " + Name + ": Invalid offset data size (" + offsetDataSize + ", expected " + (Height * 4 + 12) + ")");
                //throw new InvalidOperationException("Invalid offset data size!");
            }
            if (offsetWidth != Width)
            {
                Trace.WriteLine("RLE: " + Name + ": Invalid offset width (" + offsetWidth + ", expected " + Width + ")");
                //throw new InvalidOperationException("Invalid offset width!");
            }
            if (offsetWidth != Height)
            {
                Trace.WriteLine("RLE: " + Name + ": Invalid offset height (" + offsetWidth + ", expected " + Height + ")");
                //throw new InvalidOperationException("Invalid offset height!");
            }
            _lineOffsets = new UInt32[Height];
            start        = 64 + dataSize + 16;
            for (int i = 0; i < Height; ++i)
            {
                _lineOffsets[i] =
                    (UInt32)_rawData[start++] |
                    (UInt32)_rawData[start++] << 8 |
                        (UInt32)_rawData[start++] << 16 |
                        (UInt32)_rawData[start++] << 24;
                // Line offsets must be rising numbers
                if (i > 0 && _lineOffsets[i - 1] > _lineOffsets[i])
                {
                    Trace.WriteLine("RLE: " + Name + ": Offset data invalid");
                    throw new InvalidOperationException(Name + ": Offset data invalid!");
                }
            }
            ColorPaletteIndex =
                (UInt32)_rawData[start++] |
                (UInt32)_rawData[start++] << 8 |
                    (UInt32)_rawData[start++] << 16 |
                    (UInt32)_rawData[start++] << 24;

            // Read the pixels
            var  pixels       = new WADImagePixel[Width * Height];
            int  currentPixel = 0;
            int  max          = 64 + dataSize;
            int  pixelsToGo   = 0;
            byte opacity      = 0;

            for (int i = 64; i < max; ++i)
            {
                if (currentPixel >= pixels.Length)
                {
                    throw new InvalidOperationException("RLE: " + Name + ": There is too much pixel data.");
                }

                if (_rawData[i] == 0xFF)
                {
                    // Add transparent pixels
                    opacity = 0;
                    if (i + 1 >= max)
                    {
                        throw new InvalidOperationException("RLE: " + Name + ": End of data reached while parsing pixels.");
                    }
                    pixelsToGo = _rawData[++i];
                    for (int j = 0; j < pixelsToGo; ++j)
                    {
                        if (currentPixel >= pixels.Length)
                        {
                            throw new InvalidOperationException("RLE: " + Name + ": There is too much pixel data.");
                        }
                        pixels[currentPixel++] = new WADImagePixel()
                        {
                            Opacity = opacity
                        };
                    }
                }
                else if (_rawData[i] == 0xFE)
                {
                    opacity = 127;
                    if (i + 1 >= max)
                    {
                        throw new InvalidOperationException("RLE: " + Name + ": End of data reached while parsing pixels.");
                    }
                    pixelsToGo = _rawData[++i];
                    for (int j = 0; j < pixelsToGo; ++j)
                    {
                        if (currentPixel >= pixels.Length)
                        {
                            throw new InvalidOperationException("RLE: There is too much pixel data.");
                        }
                        if (i + 1 >= max)
                        {
                            throw new InvalidOperationException("RLE: End of data reached while parsing pixels.");
                        }
                        pixels[currentPixel++] = new WADImagePixel()
                        {
                            Opacity = opacity, PaletteValue = _rawData[++i]
                        };
                    }
                }
                else
                {
                    opacity    = 255;
                    pixelsToGo = _rawData[i];
                    for (int j = 0; j < pixelsToGo; ++j)
                    {
                        if (currentPixel >= pixels.Length)
                        {
                            throw new InvalidOperationException("RLE: " + Name + ": There is too much pixel data.");
                        }
                        if (i + 1 >= max)
                        {
                            throw new InvalidOperationException("RLE: " + Name + ": End of data reached while parsing pixels.");
                        }
                        pixels[currentPixel++] = new WADImagePixel()
                        {
                            Opacity = opacity, PaletteValue = _rawData[++i]
                        };
                    }
                }
            }

            Pixels       = new WADImagePixel[Height, Width];
            currentPixel = 0;
            for (int h = 0; h < Height; ++h)
            {
                for (int w = 0; w < Width; ++w)
                {
                    Pixels[h, w] = pixels[currentPixel++];
                }
            }
        }