Repository: python-pillow/Pillow

Issue:
Image.fromarray silently fails with floating-point input
When passing a floating-point array to ``Image.fromarray``, the output does not match the input:

```python
from PIL import Image
import numpy as np
x = np.ones((100, 100), dtype='float64')
x[40:60, 40:60] = 0.0
Image.fromarray(x, mode='L')
```
![download](https://user-images.githubusercontent.com/781659/32795726-7287ef38-c921-11e7-9da8-15736ebd2d83.png)

This happens is because when ``mode`` is specified,  the array's bytes are passed directly to ``frombuffer`` without any type check: https://github.com/python-pillow/Pillow/blob/c82f9fe1bb963ab07f995282a097757bde8f2e0f/PIL/Image.py#L2394-L2438

It would be helpful for users if the dtype of the input were checked, and an appropriate warning or error raised.

I'm using Python 3.6.1 and PIL v4.2.1


Discussion:
My impression of this parameter (which, tbh, is not well documented) is that it's for overriding the mode that's detected from the dtype. Raising an error where it doesn't match is going to be problematical for the intended use case.  On the other hand, since it's assigned directly to the rawmode as well as the mode, there are only a handful of valid modes that will work, generally the ones where the mode and rawmode match in the unpackers table in `libImaging/Unpack.c`
#4887 encountered this as well.
```python
import numpy as np
from PIL import Image

array = np.full((32,32,3),255)
Image.fromarray(array, "RGB")
```

And #5227
```python
import numpy as np
from PIL import Image

vector = np.ones((5, 5, 3)).astype("uint8") * np.array([3])
Image.fromarray(vector, mode="RGB")
```

And #5465
```python
import numpy as np
from PIL import Image
tgt = np.ones(shape=(2, 2)) # float32
tgt_im = Image.fromarray(tgt)
tgt_im_np = np.asarray(tgt_im)
final_img = Image.fromarray(tgt_im_np, mode='L')

print(np.asarray(final_img))
```

Resolving patch:
diff --git a/src/PIL/Image.py b/src/PIL/Image.py
--- a/src/PIL/Image.py
+++ b/src/PIL/Image.py
@@ -2773,7 +2773,7 @@ def fromarray(obj, mode=None):
 
       from PIL import Image
       import numpy as np
-      im = Image.open('hopper.jpg')
+      im = Image.open("hopper.jpg")
       a = np.asarray(im)
 
     Then this can be used to convert it to a Pillow image::
@@ -2781,8 +2781,21 @@ def fromarray(obj, mode=None):
       im = Image.fromarray(a)
 
     :param obj: Object with array interface
-    :param mode: Mode to use (will be determined from type if None)
-      See: :ref:`concept-modes`.
+    :param mode: Optional mode to use when reading ``obj``. Will be determined from
+      type if ``None``.
+
+      This will not be used to convert the data after reading, but will be used to
+      change how the data is read::
+
+        from PIL import Image
+        import numpy as np
+        a = np.full((1, 1), 300)
+        im = Image.fromarray(a, mode="L")
+        im.getpixel((0, 0))  # 44
+        im = Image.fromarray(a, mode="RGB")
+        im.getpixel((0, 0))  # (44, 1, 0)
+
+      See: :ref:`concept-modes` for general information about modes.
     :returns: An image object.
 
     .. versionadded:: 1.1.6


Test patch: