diff --git a/src/ImageSharp/Formats/Bmp/BmpCompression.cs b/src/ImageSharp/Formats/Bmp/BmpCompression.cs
index 5f14d2243..be275019e 100644
--- a/src/ImageSharp/Formats/Bmp/BmpCompression.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpCompression.cs
@@ -34,7 +34,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// If the first byte is zero, the record has different meanings, depending
/// on the second byte. If the second byte is zero, it is the end of the row,
/// if it is one, it is the end of the image.
- /// Not supported at the moment.
///
RLE4 = 2,
@@ -54,6 +53,13 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// The bitmap contains a PNG image.
/// Not supported at the moment.
///
- PNG = 5
+ PNG = 5,
+
+ ///
+ /// Introduced with Windows CE.
+ /// Specifies that the bitmap is not compressed and that the color table consists of four DWORD color
+ /// masks that specify the red, green, blue, and alpha components of each pixel.
+ ///
+ BI_ALPHABITFIELDS = 6
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 496a6df4a..d33ada286 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -75,7 +75,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
/// The file header containing general information.
- /// TODO: Why is this not used? We advance the stream but do not use the values parsed.
///
private BmpFileHeader fileHeader;
@@ -163,6 +162,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
break;
case BmpCompression.BitFields:
+ case BmpCompression.BI_ALPHABITFIELDS:
this.ReadBitFields(pixels, inverted);
break;
@@ -947,7 +947,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
infoHeaderType = BmpInfoHeaderType.WinVersion3;
this.infoHeader = BmpInfoHeader.ParseV3(buffer);
- // if the info header is BMP version 3 and the compression type is BITFIELDS,
+ // If the info header is BMP version 3 and the compression type is BITFIELDS,
// color masks for each color channel follow the info header.
if (this.infoHeader.Compression == BmpCompression.BitFields)
{
@@ -958,6 +958,16 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
}
+ else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS)
+ {
+ byte[] bitfieldsBuffer = new byte[16];
+ this.stream.Read(bitfieldsBuffer, 0, 16);
+ Span data = bitfieldsBuffer.AsSpan();
+ this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4));
+ this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
+ this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
+ this.infoHeader.AlphaMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(12, 4));
+ }
}
else if (headerSize == BmpInfoHeader.AdobeV3Size)
{
@@ -1078,6 +1088,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int colorMapSizeBytes = this.fileHeader.Offset - BmpFileHeader.Size - this.infoHeader.HeaderSize;
int colorCountForBitDepth = ImageMaths.GetColorCountForBitDepth(this.infoHeader.BitsPerPixel);
bytesPerColorMapEntry = colorMapSizeBytes / colorCountForBitDepth;
+
+ // Edge case for less-than-full-sized palette: bytesPerColorMapEntry should be at least 3.
+ bytesPerColorMapEntry = Math.Max(bytesPerColorMapEntry, 3);
colorMapSize = colorMapSizeBytes;
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
index e7b5aeaea..ad47ed1e7 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
@@ -60,6 +60,20 @@ namespace SixLabors.ImageSharp.Tests
}
}
+ [Theory]
+ [WithFile(RgbaAlphaBitfields, PixelTypes.Rgba32)]
+ public void BmpDecoder_CanDecodeAlphaBitfields(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ using (Image image = provider.GetImage(new BmpDecoder()))
+ {
+ image.DebugSave(provider);
+
+ // TODO: Neither System.Drawing nor MagickReferenceDecoder decode this file.
+ // image.CompareToOriginal(provider);
+ }
+ }
+
[Theory]
[WithFile(Bit32Rgba, PixelTypes.Rgba32)]
public void BmpDecoder_CanDecodeBitmap_WithAlphaChannel(TestImageProvider provider)
@@ -114,6 +128,18 @@ namespace SixLabors.ImageSharp.Tests
}
}
+ [Theory]
+ [WithFile(LessThanFullSizedPalette, PixelTypes.Rgba32)]
+ public void BmpDecoder_CanDecodeLessThanFullPalete(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ using (Image image = provider.GetImage(new BmpDecoder()))
+ {
+ image.DebugSave(provider);
+ image.CompareToOriginal(provider, new MagickReferenceDecoder());
+ }
+ }
+
[Theory]
[WithFile(Rgba32bf56, PixelTypes.Rgba32)]
public void BmpDecoder_CanDecodeAdobeBmpv3(TestImageProvider provider)
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 51e2d084c..3a497683a 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -221,6 +221,7 @@ namespace SixLabors.ImageSharp.Tests
public const string Bit8Palette4 = "Bmp/pal8-0.bmp";
public const string Os2v2Short = "Bmp/pal8os2v2-16.bmp";
public const string Os2v2 = "Bmp/pal8os2v2.bmp";
+ public const string LessThanFullSizedPalette = "Bmp/pal8os2sp.bmp";
public const string Pal8Offset = "Bmp/pal8offs.bmp";
// Bitmap images with compression type BITFIELDS
@@ -232,6 +233,7 @@ namespace SixLabors.ImageSharp.Tests
public const string Issue735 = "Bmp/issue735.bmp";
public const string Rgba32bf56 = "Bmp/rgba32h56.bmp";
public const string Rgba321010102 = "Bmp/rgba32-1010102.bmp";
+ public const string RgbaAlphaBitfields = "Bmp/rgba32abf.bmp";
public static readonly string[] BitFields
= {
diff --git a/tests/Images/Input/Bmp/pal8os2sp.bmp b/tests/Images/Input/Bmp/pal8os2sp.bmp
new file mode 100644
index 000000000..e532c8986
Binary files /dev/null and b/tests/Images/Input/Bmp/pal8os2sp.bmp differ
diff --git a/tests/Images/Input/Bmp/rgba32abf.bmp b/tests/Images/Input/Bmp/rgba32abf.bmp
new file mode 100644
index 000000000..d9bb0189c
Binary files /dev/null and b/tests/Images/Input/Bmp/rgba32abf.bmp differ