@@ -68,6 +68,21 @@ def _fn_name(): return sys._getframe(1).f_code.co_name
6868 BYTE_FORMAT = 1 # ARGB
6969
7070
71+ class ArrayWrapper :
72+ """Thin wrapper around numpy ndarray to expose the interface
73+ expected by cairocffi. Basically replicates the
74+ array.array interface.
75+ """
76+ def __init__ (self , myarray ):
77+ self .__array = myarray
78+ self .__data = myarray .ctypes .data
79+ self .__size = len (myarray .flatten ())
80+ self .itemsize = myarray .itemsize
81+
82+ def buffer_info (self ):
83+ return (self .__data , self .__size )
84+
85+
7186class RendererCairo (RendererBase ):
7287 fontweights = {
7388 100 : cairo .FONT_WEIGHT_NORMAL ,
@@ -218,9 +233,25 @@ def draw_image(self, gc, x, y, im):
218233 im = im [:, :, (2 , 1 , 0 , 3 )]
219234 else :
220235 im = im [:, :, (3 , 0 , 1 , 2 )]
221- surface = cairo .ImageSurface .create_for_data (
222- memoryview (im .flatten ()), cairo .FORMAT_ARGB32 , im .shape [1 ], im .shape [0 ],
223- im .shape [1 ]* 4 )
236+ if HAS_CAIRO_CFFI :
237+ # cairocffi tries to use the buffer_info from array.array
238+ # that we replicate in ArrayWrapper and alternatively falls back
239+ # on ctypes to get a pointer to the numpy array. This works
240+ # correctly on a numpy array in python3 but not 2.7. We replicate
241+ # the array.array functionality here to get cross version support.
242+ imbuffer = ArrayWrapper (im .flatten ())
243+ else :
244+ # py2cairo uses PyObject_AsWriteBuffer
245+ # to get a pointer to the numpy array this works correctly
246+ # on a regular numpy array but not on a memory view.
247+ # At the time of writing the latest release version of
248+ # py3cairo still does not support create_for_data
249+ imbuffer = im .flatten ()
250+ surface = cairo .ImageSurface .create_for_data (imbuffer ,
251+ cairo .FORMAT_ARGB32 ,
252+ im .shape [1 ],
253+ im .shape [0 ],
254+ im .shape [1 ]* 4 )
224255 ctx = gc .ctx
225256 y = self .height - y - im .shape [0 ]
226257
0 commit comments