static byte[] decodeMonochromeIcon(byte[] payload, CSize size) { int totalPixels = size.cx * size.cy; int maskLineDwords = (size.cx + 31) / 32; int maskStrideBytes = maskLineDwords * 4; int bytesMask = size.cy * maskStrideBytes; int cbHeader = Marshal.SizeOf <BITMAPINFOHEADER>(); // 8 is the color table, immediately after the header if (payload.Length != cbHeader + (bytesMask * 2) + 8) { throw new ArgumentException("Size doesn't match"); } byte[] image = new byte[totalPixels]; Span <byte> palette = stackalloc byte[4]; { Span <uint> colorTable = stackalloc uint[2]; payload.AsSpan() .Slice(cbHeader, 8) .castSpan <uint>() .CopyTo(colorTable); ePalette pal = getPalette(colorTable); decodePalette(pal, palette); } ReadOnlySpan <byte> bits = payload.AsSpan() .Slice(cbHeader + 8, bytesMask); ReadOnlySpan <byte> mask = payload.AsSpan() .Slice(cbHeader + 8 + bytesMask, bytesMask); if (0 == (size.cx % 32)) { // No padding whatsoever decodeMonochrome(image.AsSpan(), bits, mask, palette, totalPixels); } else { // There is some padding Span <byte> imageSpan = image.AsSpan(); int maskBytesPerLine = (size.cx + 7) / 8; int destOffset = 0; int sourceOffset = 0; for (int y = 0; y < size.cy; y++, destOffset += size.cx, sourceOffset += maskStrideBytes) { Span <byte> destSpan = imageSpan.Slice(destOffset, size.cx); ReadOnlySpan <byte> lineBits = bits.Slice(sourceOffset, maskBytesPerLine); ReadOnlySpan <byte> lineMask = mask.Slice(sourceOffset, maskBytesPerLine); decodeMonochrome(destSpan, lineBits, lineMask, palette, size.cx); } } return(image); }
static void decodePalette(ePalette pal, Span <byte> values) { Debug.Assert(values.Length == 4); // https://devblogs.microsoft.com/oldnewthing/20101018-00/?p=12513 switch (pal) { case ePalette.FirstBlack: values[0] = 0; // mask 0 image 0 = black values[1] = 0x55; // mask 0 image 1 = white values[2] = 0xAA; // mask 1 image 0 = nop values[3] = 0xFF; // mask 1 image 1 = invert break; case ePalette.FirstWhite: values[0] = 0x55; // mask 0 image 1 = white values[1] = 0; // mask 0 image 0 = black values[2] = 0xFF; // mask 1 image 1 = invert values[3] = 0xAA; // mask 1 image 0 = nop break; } }