BF: fix conversion of bit images to numpy arrays

Numpy cannot form arrays from bits.  To convert bit images to numpy,
convert bits to bytes.

From suggestion by Alexander Karpinsky, with thanks.

Fixes gh-350.
This commit is contained in:
Matthew Brett 2016-08-07 15:25:43 -07:00
parent f12febf3a9
commit 824a0c232c
3 changed files with 40 additions and 14 deletions

View File

@ -246,7 +246,7 @@ else:
_MODE_CONV = {
# official modes
"1": ('|b1', None), # broken
"1": ('|b1', None), # Bits need to be extended to bytes
"L": ('|u1', None),
"LA": ('|u1', 2),
"I": (_ENDIAN + 'i4', None),
@ -615,17 +615,21 @@ class Image(object):
self.save(b, 'PNG')
return b.getvalue()
def __getattr__(self, name):
if name == "__array_interface__":
@property
def __array_interface__(self):
# numpy array interface support
new = {}
shape, typestr = _conv_type_shape(self)
new['shape'] = shape
new['typestr'] = typestr
new['data'] = self.tobytes()
new['version'] = 3
if self.mode == '1':
# Binary images need to be extended from bits to bytes
# See: https://github.com/python-pillow/Pillow/issues/350
new['data'] = self.tobytes('raw', 'L')
else:
new['data'] = self.tobytes()
return new
raise AttributeError(name)
def __getstate__(self):
return [

View File

@ -25,13 +25,26 @@ class TestImageArray(PillowTestCase):
self.assertEqual(test("RGBX"), (3, (100, 128, 4), '|u1', 51200))
def test_fromarray(self):
class Wrapper(object):
""" Class with API matching Image.fromarray """
def __init__(self, img, arr_params):
self.img = img
self.__array_interface__ = arr_params
def tobytes(self):
return self.img.tobytes()
def test(mode):
i = im.convert(mode)
a = i.__array_interface__
a["strides"] = 1 # pretend it's non-contiguous
i.__array_interface__ = a # patch in new version of attribute
out = Image.fromarray(i)
a["strides"] = 1 # pretend it's non-contigous
# Make wrapper instance for image, new array interface
wrapped = Wrapper(i, a)
out = Image.fromarray(wrapped)
return out.mode, out.size, list(i.getdata()) == list(out.getdata())
# self.assertEqual(test("1"), ("1", (128, 100), True))
self.assertEqual(test("L"), ("L", (128, 100), True))
self.assertEqual(test("I"), ("I", (128, 100), True))

View File

@ -117,6 +117,15 @@ class TestNumpy(PillowTestCase):
self._test_img_equals_nparray(img, np_img)
self.assertEqual(np_img.dtype, numpy.dtype('<u2'))
def test_1bit(self):
# Test that 1-bit arrays convert to numpy and back
# See: https://github.com/python-pillow/Pillow/issues/350
arr = numpy.array([[1, 0, 0, 1, 0], [0, 1, 0, 0, 0]], 'u1')
img = Image.fromarray(arr * 255).convert('1')
self.assertEqual(img.mode, '1')
arr_back = numpy.array(img)
numpy.testing.assert_array_equal(arr, arr_back)
def test_save_tiff_uint16(self):
'''
Open a single-channel uint16 greyscale image and verify that it can be saved without