Repository: python-pillow/Pillow

Problem statement:
Image.fromarray does not accept array with dtype=bool
### What did you do?

```
>>> im = Image.new("1", (10,10))
>>> a = np.asarray(im)
>>> a.dtype
dtype('bool')
>>> im2 = Image.fromarray(a)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/home/moi/Dokumente/Studium/Thesis/Python/local/lib/python2.7/site-packages/PIL/Image.py", line 2167, in fromarray
    raise TypeError("Cannot handle this data type")
TypeError: Cannot handle this data type
```
### What did you expect to happen?

I expect the same image to be convertable back and forth without error.
### What versions of Pillow and Python are you using?

```
python2.7 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2]
PIL.VERSION
'1.1.7'
```



Hints:
That's a known issue. See #350

Thanks for the hint.

@wiredfool Any update on this? #350 is already closed and seems to handle 1-bit image to numpy array conversion, but not the other way around. The exception can still be reproduced following the steps given by the OP.
Note that it is even more weird that the `mode='1'` works but produces erroneous result when being read back into numpy

```python
In [62]: im = Image.new("1", (10,10))

In [63]: a = np.array(im)

In [64]: a[0][0]=True

In [65]: b = np.array(Image.fromarray(a, mode='1'), dtype=np.bool)

In [66]: b
Out[66]:
array([[False, False, False, False, False, False, False,  True, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False]], dtype=bool)

In [67]: b[0][7]
Out[67]: True
```
So the minimal replication is:
```
a = np.zeros((2,10), dtype=np.bool)
>>> a[0][0] = True 
>>> a
array([[ True, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False]], dtype=bool)
>>> im2 = Image.fromarray(a, '1')
>>> list(im2.getdata())[:10]
[0, 0, 0, 0, 0, 0, 0, 255, 0, 0]
```

We don't actually advertise that we support the '|b1' typestr in the array interface for a, and there's no way to pass in some form of mode/rawmode combo. So when you pass in the '1' mode, it's expecting a bit packed buffer, which is not what's actually coming through. 

Patch:
diff --git a/PIL/Image.py b/PIL/Image.py
--- a/PIL/Image.py
+++ b/PIL/Image.py
@@ -2423,7 +2423,7 @@ def fromqpixmap(im):
 _fromarray_typemap = {
     # (shape, typestr) => mode, rawmode
     # first two members of shape are set to one
-    # ((1, 1), "|b1"): ("1", "1"), # broken
+    ((1, 1), "|b1"): ("1", "1;8"), 
     ((1, 1), "|u1"): ("L", "L"),
     ((1, 1), "|i1"): ("I", "I;8"),
     ((1, 1), "<u2"): ("I", "I;16"),


Test patch:
diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py
--- a/Tests/test_numpy.py
+++ b/Tests/test_numpy.py
@@ -39,7 +39,7 @@ def test_numpy_to_image(self):
         def to_image(dtype, bands=1, boolean=0):
             if bands == 1:
                 if boolean:
-                    data = [0, 1] * 50
+                    data = [0, 255] * 50
                 else:
                     data = list(range(100))
                 a = numpy.array(data, dtype=dtype)
@@ -58,9 +58,9 @@ def to_image(dtype, bands=1, boolean=0):
             return i
 
         # Check supported 1-bit integer formats
-        self.assertRaises(TypeError, lambda: to_image(numpy.bool))
-        self.assertRaises(TypeError, lambda: to_image(numpy.bool8))
-
+        self.assert_image(to_image(numpy.bool, 1, 1), '1', TEST_IMAGE_SIZE)
+        self.assert_image(to_image(numpy.bool8, 1, 1), '1', TEST_IMAGE_SIZE)
+        
         # Check supported 8-bit integer formats
         self.assert_image(to_image(numpy.uint8), "L", TEST_IMAGE_SIZE)
         self.assert_image(to_image(numpy.uint8, 3), "RGB", TEST_IMAGE_SIZE)
@@ -213,5 +213,13 @@ def test_zero_size(self):
         self.assertEqual(im.size, (0, 0))
 
 
+    def test_bool(self):
+        # https://github.com/python-pillow/Pillow/issues/2044
+        a = numpy.zeros((10,2), dtype=numpy.bool)
+        a[0][0] = True 
+
+        im2 = Image.fromarray(a)
+        self.assertEqual(im2.getdata()[0], 255)
+
 if __name__ == '__main__':
     unittest.main()