@@ -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 ,
@@ -175,9 +190,25 @@ def draw_image(self, gc, x, y, im):
175190 im = im [:, :, (2 , 1 , 0 , 3 )]
176191 else :
177192 im = im [:, :, (3 , 0 , 1 , 2 )]
178- surface = cairo .ImageSurface .create_for_data (
179- memoryview (im .flatten ()), cairo .FORMAT_ARGB32 , im .shape [1 ], im .shape [0 ],
180- im .shape [1 ]* 4 )
193+ if HAS_CAIRO_CFFI :
194+ # cairocffi tries to use the buffer_info from array.array
195+ # that we replicate in ArrayWrapper and alternatively falls back
196+ # on ctypes to get a pointer to the numpy array. This works
197+ # correctly on a numpy array in python3 but not 2.7. We replicate
198+ # the array.array functionality here to get cross version support.
199+ imbuffer = ArrayWrapper (im .flatten ())
200+ else :
201+ # py2cairo uses PyObject_AsWriteBuffer
202+ # to get a pointer to the numpy array this works correctly
203+ # on a regular numpy array but not on a memory view.
204+ # At the time of writing the latest release version of
205+ # py3cairo still does not support create_for_data
206+ imbuffer = im .flatten ()
207+ surface = cairo .ImageSurface .create_for_data (imbuffer ,
208+ cairo .FORMAT_ARGB32 ,
209+ im .shape [1 ],
210+ im .shape [0 ],
211+ im .shape [1 ]* 4 )
181212 ctx = gc .ctx
182213 y = self .height - y - im .shape [0 ]
183214
0 commit comments