Skip to content

Commit f4fee35

Browse files
Support the new Python 3 buffer interface to get the Agg renderer buffer.
Supported by Sage Days 29
1 parent 749f295 commit f4fee35

File tree

10 files changed

+70
-28
lines changed

10 files changed

+70
-28
lines changed

CXX/Python3/ExtensionTypeBase.hxx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ namespace Py
121121
virtual Object number_power( const Object &, const Object & );
122122

123123
// Buffer
124-
// QQQ need to add py3 interface
124+
virtual int buffer_get( Py_buffer *, int flags );
125+
virtual int buffer_release( Py_buffer *buf );
125126

126127
public:
127128
// helper functions to call function fn_name with 0 to 9 args

CXX/Python3/cxx_extensions.cxx

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@ extern "C"
262262
static PyObject *number_power_handler( PyObject *, PyObject *, PyObject * );
263263

264264
// Buffer
265-
// QQQ
265+
static int buffer_get_handler( PyObject *, Py_buffer *, int );
266+
static void buffer_release_handler( PyObject *, Py_buffer * );
266267
}
267268

268269
extern "C" void standard_dealloc( PyObject *p )
@@ -345,8 +346,8 @@ PythonType &PythonType::supportBufferType()
345346
buffer_table = new PyBufferProcs;
346347
memset( buffer_table, 0, sizeof( PyBufferProcs ) ); // ensure new fields are 0
347348
table->tp_as_buffer = buffer_table;
348-
// QQQ bf_getbuffer
349-
// QQQ bf_releasebuffer
349+
buffer_table->bf_getbuffer = buffer_get_handler;
350+
buffer_table->bf_releasebuffer = buffer_release_handler;
350351
}
351352
return *this;
352353
}
@@ -1099,6 +1100,25 @@ extern "C" PyObject *number_power_handler( PyObject *self, PyObject *x1, PyObjec
10991100
}
11001101

11011102
// Buffer
1103+
extern "C" int buffer_get_handler( PyObject *self, Py_buffer *buf, int flags )
1104+
{
1105+
try
1106+
{
1107+
PythonExtensionBase *p = getPythonExtensionBase( self );
1108+
return p->buffer_get( buf, flags );
1109+
}
1110+
catch( Py::Exception & )
1111+
{
1112+
return -1; // indicate error
1113+
}
1114+
}
1115+
1116+
extern "C" void buffer_release_handler( PyObject *self, Py_buffer *buf )
1117+
{
1118+
PythonExtensionBase *p = getPythonExtensionBase( self );
1119+
p->buffer_release( buf );
1120+
// NOTE: No way to indicate error to Python
1121+
}
11021122

11031123
//================================================================================
11041124
//
@@ -1454,7 +1474,18 @@ Py::Object PythonExtensionBase::number_power( const Py::Object &, const Py::Obje
14541474

14551475

14561476
// Buffer
1457-
// QQQ
1477+
int PythonExtensionBase::buffer_get( Py_buffer *buf, int flags )
1478+
{
1479+
missing_method( buffer_get );
1480+
return -1;
1481+
}
1482+
1483+
int PythonExtensionBase::buffer_release( Py_buffer *buf )
1484+
{
1485+
/* This method is optional and only required if the buffer's
1486+
memory is dynamic. */
1487+
return 0;
1488+
}
14581489

14591490
//--------------------------------------------------------------------------------
14601491
//

examples/pylab_examples/agg_buffer_to_array.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
fig.canvas.draw()
1111

1212
# grab rhe pixel buffer and dumpy it into a numpy array
13-
buf = fig.canvas.buffer_rgba(0,0)
13+
buf = fig.canvas.buffer_rgba()
1414
l, b, w, h = fig.bbox.bounds
1515
X = np.frombuffer(buf, np.uint8)
1616
X.shape = h,w,4

lib/matplotlib/backends/backend_agg.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,10 @@ def tostring_argb(self):
249249
'debug-annoying')
250250
return self._renderer.tostring_argb()
251251

252-
def buffer_rgba(self,x,y):
252+
def buffer_rgba(self):
253253
if __debug__: verbose.report('RendererAgg.buffer_rgba',
254254
'debug-annoying')
255-
return self._renderer.buffer_rgba(x,y)
255+
return self._renderer.buffer_rgba()
256256

257257
def clear(self):
258258
self._renderer.clear()
@@ -421,10 +421,10 @@ def tostring_argb(self):
421421
'debug-annoying')
422422
return self.renderer.tostring_argb()
423423

424-
def buffer_rgba(self,x,y):
424+
def buffer_rgba(self):
425425
if __debug__: verbose.report('FigureCanvasAgg.buffer_rgba',
426426
'debug-annoying')
427-
return self.renderer.buffer_rgba(x,y)
427+
return self.renderer.buffer_rgba()
428428

429429
def get_default_filetype(self):
430430
return 'png'
@@ -447,7 +447,7 @@ def print_png(self, filename_or_obj, *args, **kwargs):
447447
renderer.dpi = self.figure.dpi
448448
if is_string_like(filename_or_obj):
449449
filename_or_obj = open(filename_or_obj, 'wb')
450-
_png.write_png(renderer._renderer.buffer_rgba(0, 0),
450+
_png.write_png(renderer._renderer.buffer_rgba(),
451451
renderer.width, renderer.height,
452452
filename_or_obj, self.figure.dpi)
453453
renderer.dpi = original_dpi
@@ -457,7 +457,7 @@ def print_to_buffer(self):
457457
renderer = self.get_renderer()
458458
original_dpi = renderer.dpi
459459
renderer.dpi = self.figure.dpi
460-
result = (renderer._renderer.buffer_rgba(0, 0),
460+
result = (renderer._renderer.buffer_rgba(),
461461
(int(renderer.width), int(renderer.height)))
462462
renderer.dpi = original_dpi
463463
return result

lib/matplotlib/backends/backend_cocoaagg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def updatePlot(self):
144144
self.image_.setSize_((w,h))
145145

146146
brep = NSBitmapImageRep.alloc().initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel_(
147-
(self.canvas.buffer_rgba(0,0),'','','',''), # Image data
147+
(self.canvas.buffer_rgba(),'','','',''), # Image data
148148
w, # width
149149
h, # height
150150
8, # bits per pixel

lib/matplotlib/backends/backend_fltkagg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def draw(self):
108108
self._source.resize(newsize)
109109
self._source.draw()
110110
t1,t2,w,h = self._source.figure.bbox.bounds
111-
Fltk.fl_draw_image(self._source.buffer_rgba(0,0),0,0,int(w),int(h),4,0)
111+
Fltk.fl_draw_image(self._source.buffer_rgba(),0,0,int(w),int(h),4,0)
112112
self.redraw()
113113

114114
def blit(self,bbox=None):
@@ -118,7 +118,7 @@ def blit(self,bbox=None):
118118
t1o,t2o,wo,ho = self._source.figure.bbox.bounds
119119
t1,t2,w,h = bbox.bounds
120120
x,y=int(t1),int(t2)
121-
Fltk.fl_draw_image(self._source.buffer_rgba(x,y),x,y,int(w),int(h),4,int(wo)*4)
121+
Fltk.fl_draw_image(self._source.buffer_rgba(),x,y,int(w),int(h),4,int(wo)*4)
122122
#self.redraw()
123123

124124
def handle(self, event):

lib/matplotlib/backends/backend_gtkagg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def _render_figure(self, pixmap, width, height):
7676
if DEBUG: print('FigureCanvasGTKAgg.render_figure pixmap', pixmap)
7777
#agg_to_gtk_drawable(pixmap, self.renderer._renderer, None)
7878

79-
buf = self.buffer_rgba(0,0)
79+
buf = self.buffer_rgba()
8080
ren = self.get_renderer()
8181
w = int(ren.width)
8282
h = int(ren.height)

lib/matplotlib/backends/backend_wxagg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def _convert_agg_to_wx_bitmap(agg, bbox):
160160
if bbox is None:
161161
# agg => rgba buffer -> bitmap
162162
return wx.BitmapFromBufferRGBA(int(agg.width), int(agg.height),
163-
agg.buffer_rgba(0, 0))
163+
agg.buffer_rgba())
164164
else:
165165
# agg => rgba buffer -> bitmap => clipped bitmap
166166
return _WX28_clipped_agg_as_bitmap(agg, bbox)
@@ -177,7 +177,7 @@ def _WX28_clipped_agg_as_bitmap(agg, bbox):
177177
t = b + height
178178

179179
srcBmp = wx.BitmapFromBufferRGBA(int(agg.width), int(agg.height),
180-
agg.buffer_rgba(0, 0))
180+
agg.buffer_rgba())
181181
srcDC = wx.MemoryDC()
182182
srcDC.SelectObject(srcBmp)
183183

src/_backend_agg.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,19 +2191,13 @@ RendererAgg::buffer_rgba(const Py::Tuple& args)
21912191

21922192
_VERBOSE("RendererAgg::buffer_rgba");
21932193

2194-
args.verify_length(2);
2195-
int startw = Py::Int(args[0]);
2196-
int starth = Py::Int(args[1]);
2197-
int row_len = width * 4;
2198-
int start = row_len * starth + startw * 4;
2194+
args.verify_length(0);
21992195

22002196
#if PY3K
2201-
Py_buffer view;
2202-
PyBuffer_FillInfo(&view, NULL, (void *)((const char *)pixBuffer + start),
2203-
row_len*height - start, 1, PyBUF_SIMPLE);
2204-
return Py::asObject(PyMemoryView_FromBuffer(&view));
2197+
return Py::asObject(this);
22052198
#else
2206-
return Py::asObject(PyBuffer_FromMemory(pixBuffer + start, row_len*height - start));
2199+
int row_len = width * 4;
2200+
return Py::asObject(PyBuffer_FromMemory(pixBuffer, row_len*height));
22072201
#endif
22082202
}
22092203

@@ -2318,6 +2312,14 @@ RendererAgg::points_to_pixels(const Py::Object& points)
23182312
return p * dpi / 72.0;
23192313
}
23202314

2315+
#if PY3K
2316+
int
2317+
RendererAgg::buffer_get( Py_buffer* buf, int flags )
2318+
{
2319+
return PyBuffer_FillInfo(buf, this, pixBuffer, width * height * 4, 1,
2320+
PyBUF_SIMPLE);
2321+
}
2322+
#endif
23212323

23222324
RendererAgg::~RendererAgg()
23232325
{
@@ -2439,6 +2441,10 @@ void RendererAgg::init_type()
24392441
"restore_region(region)");
24402442
add_varargs_method("restore_region2", &RendererAgg::restore_region2,
24412443
"restore_region(region, x1, y1, x2, y2, x3, y3)");
2444+
2445+
#if PY3K
2446+
behaviors().supportBufferType();
2447+
#endif
24422448
}
24432449

24442450
PyMODINIT_FUNC

src/_backend_agg.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ class RendererAgg: public Py::PythonExtension<RendererAgg>
195195
Py::Object restore_region(const Py::Tuple & args);
196196
Py::Object restore_region2(const Py::Tuple & args);
197197

198+
#if PY3K
199+
virtual int buffer_get( Py_buffer *, int flags );
200+
#endif
201+
198202
virtual ~RendererAgg();
199203

200204
static const size_t PIXELS_PER_INCH;

0 commit comments

Comments
 (0)