I'm getting an error from the following Python3 code, in the indicated lines. x, y, and z are all plain 2D numpy arrays identical but for size, and ought to work the same. Yet they act differently, with y and z crashing while x works fine.
import numpy as np
from PIL import Image
a = np.ones( ( 3,3,3), dtype='uint8' )
x = a[1,:,:]
y = a[:,1,:]
z = a[:,:,1]
imx = Image.fromarray(x) # ok
imy = Image.fromarray(y) # error
imz = Image.fromarray(z) # error
but this works
z1 = 1*z
imz = Image.fromarray(z1) # ok
The error is:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python3\lib\site-packages\PIL\Image.py", line 1918, in fromarray
obj = obj.tobytes()
AttributeError: 'numpy.ndarray' object has no attribute 'tobytes'
So what's different between x, y, z, z1? Nothing that I can tell.
>>> z.dtype
dtype('uint8')
>>> z1.dtype
dtype('uint8')
>>> z.shape
(3, 4)
>>> z1.shape
(3, 4)
I'm using Python 3.2.3 on a Windows 7 Enterprise machine, with everything 64 bit.
I can reproduce on ubuntu 12.04 with Python 3.2.3, numpy 1.6.1, and PIL 1.1.7-for-Python 3 at http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil. The difference happens because the array_interface of x doesn't have a strides value but y's and z's do:
>>> x.__array_interface__['strides']
>>> y.__array_interface__['strides']
(9, 1)
>>> z.__array_interface__['strides']
(9, 3)
and so a different branch is taken here:
if strides is not None:
obj = obj.tobytes()
The documentation mentions tostring
, not tobytes
:
# If obj is not contiguous, then the tostring method is called
# and {@link frombuffer} is used.
And the Python 2 source of PIL 1.1.7 uses tostring
:
if strides is not None:
obj = obj.tostring()
so I suspect that this was an error introduced during a 2-to-3 conversion in which str/bytes changes were made. Simply replace tobytes()
by tostring()
in Image.py
and it should work:
Python 3.2.3 (default, May 3 2012, 15:54:42)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> from PIL import Image
>>>
>>> a = np.ones( ( 3,3,3), dtype='uint8' )
>>> x = a[1,:,:]
>>> y = a[:,1,:]
>>> z = a[:,:,1]
>>>
>>> imx = Image.fromarray(x) # ok
>>> imy = Image.fromarray(y) # now no error!
>>> imz = Image.fromarray(z) # now no error!
>>>