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); }
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++]; } } }
/// <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++]; } } }