Repository: python-pillow/Pillow

Issue:
Support for more bitfields in bmp
Image format: 32bpp BMP with bitfields

I am wondering if supporting bitfields with the following configuration

```python
                     (0xff, 0xff00, 0xff0000, 0xff000000),
```
is in scope

Currently, it is not supported
https://github.com/python-pillow/Pillow/blob/2fa54408d46411be9978e3b7ec6a5c70f44e09ab/src/PIL/BmpImagePlugin.py#L159-L166

The idea is that these bitfields allow one to store a contiguous C ordered `RGBA` array in memory and just dump it tofile. Doing so, I get a nice 20% boost in speed compared to pillow. But if I save my files in this format, PILLOW can't open them.

That said, pillow is kinda ubiquitous and saving in a BMP format that isn't supported by pillow is a little too dangerous for my taste.

I'm glad to submit a PR, but help navigating the Pillow database would be appreciated.


Discussion:
Are you able to provide an image saved in that way, to be added to the test suite under the Pillow license?

Resolving patch:
diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py
--- a/src/PIL/BmpImagePlugin.py
+++ b/src/PIL/BmpImagePlugin.py
@@ -180,6 +180,7 @@ def _bitmap(self, header=0, offset=0):
             SUPPORTED = {
                 32: [(0xff0000, 0xff00, 0xff, 0x0),
                      (0xff0000, 0xff00, 0xff, 0xff000000),
+                     (0xff, 0xff00, 0xff0000, 0xff000000),
                      (0x0, 0x0, 0x0, 0x0),
                      (0xff000000, 0xff0000, 0xff00, 0x0)],
                 24: [(0xff0000, 0xff00, 0xff)],
@@ -188,6 +189,7 @@ def _bitmap(self, header=0, offset=0):
             MASK_MODES = {
                 (32, (0xff0000, 0xff00, 0xff, 0x0)): "BGRX",
                 (32, (0xff000000, 0xff0000, 0xff00, 0x0)): "XBGR",
+                (32, (0xff, 0xff00, 0xff0000, 0xff000000)): "RGBA",
                 (32, (0xff0000, 0xff00, 0xff, 0xff000000)): "BGRA",
                 (32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
                 (24, (0xff0000, 0xff00, 0xff)): "BGR",
@@ -200,7 +202,7 @@ def _bitmap(self, header=0, offset=0):
                     raw_mode = MASK_MODES[
                         (file_info["bits"], file_info["rgba_mask"])
                     ]
-                    self.mode = "RGBA" if raw_mode in ("BGRA",) else self.mode
+                    self.mode = "RGBA" if "A" in raw_mode else self.mode
                 elif (file_info['bits'] in (24, 16) and
                       file_info['rgb_mask'] in SUPPORTED[file_info['bits']]):
                     raw_mode = MASK_MODES[


Test patch:
diff --git a/Tests/images/rgb32bf-rgba.bmp b/Tests/images/rgb32bf-rgba.bmp
new file mode 100644
Binary files /dev/null and b/Tests/images/rgb32bf-rgba.bmp differ
diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py
--- a/Tests/test_file_bmp.py
+++ b/Tests/test_file_bmp.py
@@ -90,3 +90,15 @@ def test_save_dib(self):
         self.assertEqual(reloaded.format, "DIB")
         self.assertEqual(reloaded.get_format_mimetype(), "image/bmp")
         self.assert_image_equal(im, reloaded)
+
+    def test_rgba_bitfields(self):
+        # This test image has been manually hexedited
+        # to change the bitfield compression in the header from XBGR to RGBA
+        im = Image.open("Tests/images/rgb32bf-rgba.bmp")
+
+        # So before the comparing the image, swap the channels
+        b, g, r = im.split()[1:]
+        im = Image.merge("RGB", (r, g, b))
+
+        target = Image.open("Tests/images/bmp/q/rgb32bf-xbgr.bmp")
+        self.assert_image_equal(im, target)