Repository: python-pillow/Pillow

Issue:
`BGR;[15,16,34,32]` modes are documented but not part of `ImageMode`
I found a few image modes that are listed as partially supported in the docs ([here](https://pillow.readthedocs.io/en/stable/handbook/concepts.html)), but that are not listed in `ImageMode`:

```python
from PIL import ImageMode

# note: I'm using the private variable here because it supports `in`
# and leads to nicer code
# afaik correct access is done via ImageMode.getmode(mode)

assert "BGR;15" in ImageMode._modes
assert "BGR;16" in ImageMode._modes
assert "BGR;24" in ImageMode._modes
assert "BGR;32" in ImageMode._modes
```

Is there any reason why these have not been added? If not, would a PR adding those be welcome?


Discussion:
On that note, is there any chance to add `"1;8"` as an official mode and not just a rawmode?

I might be going about this the wrong way, but I can't seem to figure out how to save a boolean array while setting the mode explicitly:

```python
image = np.arange(256 * 256).reshape((256, 256)) % 2 == 0

Image.fromarray(expected).save("fancy.png")  # works
Image.fromarray(expected, mode="1").save("fancy.png")  # saves corrupted image
Image.fromarray(expected, mode="1;8").save("fancy.png")  # invalid mode
```
I think when I documented BGR;* in #4047, I was just working from https://github.com/python-pillow/Pillow/blob/3f77466f11e04ddefdbbe79de6511ff8fb0b087b/src/libImaging/Storage.c#L131-L155

The support for those modes is not great - `BGR;32` isn't even mentioned anywhere else in `src`.

That said, I don't see any problem with a PR adding those modes to ImageMode.

---

`Image.fromarray(expected).save("fancy.png")` goes through
https://github.com/python-pillow/Pillow/blob/3f77466f11e04ddefdbbe79de6511ff8fb0b087b/src/PIL/Image.py#L2806-L2816
to come out with a `mode` of 1 and a `rawmode` of `1;8` - so yes, I'm not surprised that you can't get the same result when explicitly setting the mode, which would lead to identical values for `mode` and `rawmode`.

But I'm also not clear on why you need to set the mode explicitly?
> The support for those modes is not great - BGR;32 isn't even mentioned anywhere else in src.

I agree, I never saw this mode in real code neither. 

My motivation for doing this is a refactor in our codebase that makes it lean on `ImageMode` instead of maintaining our own list of channels for each mode, which could go out of sync as pillow improves. I noticed that those modes are missing, so I think it makes sense to make that list complete.

---

> But I'm also not clear on why you need to set the mode [`1;8`] explicitly?

Because I was writing a unit-test and it caught me off guard that the following round trip fails:

```python
# a boolean ndarray saved as b/w
expected = np.arange(256 * 256).reshape((256, 256)) % 2 == 0
Image.fromarray(expected, mode="1").save("fancy.png")
actual = np.asarray(Image.open("fancy.png"))

assert np.allclose(actual, expected)
```

In my case, the solution was to drop `mode=1` completely, but it is unexpected that the above does not work. From here, I did some searching on what the correct `mode=XX` value should be, but it seems that it is impossible to set the mode explicitly for this scenario. Instead, it _has_ to be resolved implicitly by pillow using the shape and dtype of the array.

Resolving patch:
diff --git a/src/PIL/ImageMode.py b/src/PIL/ImageMode.py
--- a/src/PIL/ImageMode.py
+++ b/src/PIL/ImageMode.py
@@ -52,6 +52,10 @@ def getmode(mode):
             "HSV": ("RGB", "L", ("H", "S", "V")),
             # extra experimental modes
             "RGBa": ("RGB", "L", ("R", "G", "B", "a")),
+            "BGR;15": ("RGB", "L", ("B", "G", "R")),
+            "BGR;16": ("RGB", "L", ("B", "G", "R")),
+            "BGR;24": ("RGB", "L", ("B", "G", "R")),
+            "BGR;32": ("RGB", "L", ("B", "G", "R")),
             "LA": ("L", "L", ("L", "A")),
             "La": ("L", "L", ("L", "a")),
             "PA": ("RGB", "L", ("P", "A")),


Test patch: