static DecodedBitmap DecodeBitmap(BitmapInfoHeader header, IList <Rgb> palette, byte[] data) { if (header.BitmapCompression != BitmapCompression.None) { return(null); } DecodedBitmap bitmap = new DecodedBitmap { BitsPerPixel = header.BitsPerPlane, Height = header.Height, Width = header.Width, Pixels = new int[header.Width * header.Height] }; int[] argbPalette = new int[palette.Count]; for (int c = 0; c < palette.Count; c++) { argbPalette[c] = (palette[c].Red << 16) + (palette[c].Green << 8) + palette[c].Blue; } long pos = 0; for (int y = 0; y < bitmap.Height; y++) { int x = 0; while (x < bitmap.Width) { for (int k = (int)(8 - bitmap.BitsPerPixel); k >= 0; k -= (int)bitmap.BitsPerPixel) { bitmap.Pixels[y * bitmap.Width + x] = argbPalette[(data[pos] >> k) & ((1 << (int)bitmap.BitsPerPixel) - 1)]; x++; if (x == bitmap.Width) { break; } } pos++; } pos += pos % 2; } return(bitmap); }
/// <summary> /// This will decode an icon /// </summary> /// <param name="data">Data</param> /// <returns>A <see cref="DecodedBitmap" /> with the icon, null if the icon could not be decoded</returns> public static DecodedBitmap DecodeIcon(byte[] data) { long pos = 0; byte[] buffer = new byte[Marshal.SizeOf(typeof(BitmapInfoHeader))]; Array.Copy(data, pos, buffer, 0, buffer.Length); BitmapInfoHeader bitmapFileHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian <BitmapInfoHeader>(buffer); // Stop at unknown header if (bitmapFileHeader.HeaderSize != 40) { return(null); } // Multiplanes not supported if (bitmapFileHeader.Planes != 1) { return(null); } // TODO: Non paletted? pos += bitmapFileHeader.HeaderSize; Rgb[] palette = new Rgb[1 << bitmapFileHeader.BitsPerPlane]; buffer = new byte[Marshal.SizeOf(typeof(Rgb))]; for (int i = 0; i < palette.Length; i++) { Array.Copy(data, pos, buffer, 0, buffer.Length); pos += buffer.Length; palette[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <Rgb>(buffer); } // First let's do the icon itself bitmapFileHeader.Height /= 2; long dataLength = 0; for (int y = 0; y < bitmapFileHeader.Height; y++) { int x = 0; while (x < bitmapFileHeader.Width) { for (int k = 8 - bitmapFileHeader.BitsPerPlane; k >= 0; k -= (int)bitmapFileHeader.BitsPerPlane) { x++; } dataLength++; } dataLength += dataLength % 2; } buffer = new byte[dataLength]; Array.Copy(data, pos, buffer, 0, buffer.Length); DecodedBitmap icon = DecodeBitmap(bitmapFileHeader, palette, buffer); // Then the mask pos += dataLength; bitmapFileHeader.BitsPerPlane = 1; dataLength = 0; for (int y = 0; y < bitmapFileHeader.Height; y++) { int x = 0; while (x < bitmapFileHeader.Width) { for (int k = 8 - bitmapFileHeader.BitsPerPlane; k >= 0; k -= (int)bitmapFileHeader.BitsPerPlane) { x++; } dataLength++; } dataLength += dataLength % 2; } buffer = new byte[dataLength]; Array.Copy(data, pos, buffer, 0, buffer.Length); DecodedBitmap mask = DecodeBitmap(bitmapFileHeader, palette, buffer); // Mask palette int[] argbPalette = new int[palette.Length]; for (int c = 0; c < palette.Length; c++) { argbPalette[c] = (palette[c].Red << 16) + (palette[c].Green << 8) + palette[c].Blue; } DecodedBitmap bitmap = new DecodedBitmap { BitsPerPixel = icon.BitsPerPixel, Height = icon.Height, Width = icon.Width, Pixels = new int[icon.Pixels.Length] }; for (int px = 0; px < bitmap.Pixels.Length; px++) { bitmap.Pixels[px] = icon.Pixels[px] + (mask.Pixels[px] == argbPalette[0] ? VISIBLE : 0); } // Need to reverse first all pixels then by line int[] pixels = bitmap.Pixels.Reverse().ToArray(); for (int y = 0; y < bitmap.Height; y++) { for (int x = 0; x < bitmap.Width; x++) { bitmap.Pixels[y * bitmap.Width + (bitmap.Width - x - 1)] = pixels[y * bitmap.Width + x]; } } return(bitmap); }