Skip to content

Commit bc9eb96

Browse files
authored
Merge pull request #17788 from anntzer/rgbamin
Tighten a bit the RendererAgg API.
2 parents 98961f6 + c3e1c1b commit bc9eb96

File tree

6 files changed

+45
-67
lines changed

6 files changed

+45
-67
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
``RendererAgg.get_content_extents``, ``RendererAgg.tostring_rgba_minimized``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
... are deprecated.

lib/matplotlib/backends/backend_agg.py

+16-11
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,15 @@ def _update_methods(self):
116116
# self.draw_path_collection = self._renderer.draw_path_collection
117117
self.draw_quad_mesh = self._renderer.draw_quad_mesh
118118
self.copy_from_bbox = self._renderer.copy_from_bbox
119-
self.get_content_extents = self._renderer.get_content_extents
120119

120+
@cbook.deprecated("3.4")
121+
def get_content_extents(self):
122+
orig_img = np.asarray(self.buffer_rgba())
123+
slice_y, slice_x = cbook._get_nonzero_slices(orig_img[..., 3])
124+
return (slice_x.start, slice_y.start,
125+
slice_x.stop - slice_x.start, slice_y.stop - slice_y.start)
126+
127+
@cbook.deprecated("3.4")
121128
def tostring_rgba_minimized(self):
122129
extents = self.get_content_extents()
123130
bbox = [[extents[0], self.height - (extents[1] + extents[3])],
@@ -364,23 +371,21 @@ def post_processing(image, dpi):
364371
The saved renderer is restored and the returned image from
365372
post_processing is plotted (using draw_image) on it.
366373
"""
367-
368-
width, height = int(self.width), int(self.height)
369-
370-
buffer, (l, b, w, h) = self.tostring_rgba_minimized()
374+
orig_img = np.asarray(self.buffer_rgba())
375+
slice_y, slice_x = cbook._get_nonzero_slices(orig_img[..., 3])
376+
cropped_img = orig_img[slice_y, slice_x]
371377

372378
self._renderer = self._filter_renderers.pop()
373379
self._update_methods()
374380

375-
if w > 0 and h > 0:
376-
img = np.frombuffer(buffer, np.uint8)
377-
img, ox, oy = post_processing(img.reshape((h, w, 4)) / 255.,
378-
self.dpi)
381+
if cropped_img.size:
382+
img, ox, oy = post_processing(cropped_img / 255, self.dpi)
379383
gc = self.new_gc()
380384
if img.dtype.kind == 'f':
381385
img = np.asarray(img * 255., np.uint8)
382-
img = img[::-1]
383-
self._renderer.draw_image(gc, l + ox, height - b - h + oy, img)
386+
self._renderer.draw_image(
387+
gc, slice_x.start + ox, int(self.height) - slice_y.stop + oy,
388+
img[::-1])
384389

385390

386391
class FigureCanvasAgg(FigureCanvasBase):

lib/matplotlib/backends/backend_mixed.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22

3+
from matplotlib import cbook
34
from matplotlib.backends.backend_agg import RendererAgg
45
from matplotlib.tight_bbox import process_figure_for_rasterizing
56

@@ -98,21 +99,19 @@ def stop_rasterizing(self):
9899
self._renderer = self._vector_renderer
99100

100101
height = self._height * self.dpi
101-
buffer, bounds = self._raster_renderer.tostring_rgba_minimized()
102-
l, b, w, h = bounds
103-
if w > 0 and h > 0:
104-
image = np.frombuffer(buffer, dtype=np.uint8)
105-
image = image.reshape((h, w, 4))
106-
image = image[::-1]
102+
img = np.asarray(self._raster_renderer.buffer_rgba())
103+
slice_y, slice_x = cbook._get_nonzero_slices(img[..., 3])
104+
cropped_img = img[slice_y, slice_x]
105+
if cropped_img.size:
107106
gc = self._renderer.new_gc()
108107
# TODO: If the mixedmode resolution differs from the figure's
109108
# dpi, the image must be scaled (dpi->_figdpi). Not all
110109
# backends support this.
111110
self._renderer.draw_image(
112111
gc,
113-
l * self._figdpi / self.dpi,
114-
(height-b-h) * self._figdpi / self.dpi,
115-
image)
112+
slice_x.start * self._figdpi / self.dpi,
113+
(height - slice_y.stop) * self._figdpi / self.dpi,
114+
cropped_img[::-1])
116115
self._raster_renderer = None
117116

118117
# restore the figure dpi.

lib/matplotlib/cbook/__init__.py

+18
Original file line numberDiff line numberDiff line change
@@ -2162,6 +2162,24 @@ def _unmultiplied_rgba8888_to_premultiplied_argb32(rgba8888):
21622162
return argb32
21632163

21642164

2165+
def _get_nonzero_slices(buf):
2166+
"""
2167+
Return the bounds of the nonzero region of a 2D array as a pair of slices.
2168+
2169+
``buf[_get_nonzero_slices(buf)]`` is the smallest sub-rectangle in *buf*
2170+
that encloses all non-zero entries in *buf*. If *buf* is fully zero, then
2171+
``(slice(0, 0), slice(0, 0))`` is returned.
2172+
"""
2173+
x_nz, = buf.any(axis=0).nonzero()
2174+
y_nz, = buf.any(axis=1).nonzero()
2175+
if len(x_nz) and len(y_nz):
2176+
l, r = x_nz[[0, -1]]
2177+
b, t = y_nz[[0, -1]]
2178+
return slice(b, t + 1), slice(l, r + 1)
2179+
else:
2180+
return slice(0, 0), slice(0, 0)
2181+
2182+
21652183
def _pformat_subprocess(command):
21662184
"""Pretty-format a subprocess command for printing/logging purposes."""
21672185
return (command if isinstance(command, str)

src/_backend_agg.cpp

-35
Original file line numberDiff line numberDiff line change
@@ -167,41 +167,6 @@ bool RendererAgg::render_clippath(py::PathIterator &clippath,
167167
return has_clippath;
168168
}
169169

170-
agg::rect_i RendererAgg::get_content_extents()
171-
{
172-
agg::rect_i r(width, height, 0, 0);
173-
174-
// Looks at the alpha channel to find the minimum extents of the image
175-
unsigned char *pixel = pixBuffer + 3;
176-
for (int y = 0; y < (int)height; ++y) {
177-
for (int x = 0; x < (int)width; ++x) {
178-
if (*pixel) {
179-
if (x < r.x1)
180-
r.x1 = x;
181-
if (y < r.y1)
182-
r.y1 = y;
183-
if (x > r.x2)
184-
r.x2 = x;
185-
if (y > r.y2)
186-
r.y2 = y;
187-
}
188-
pixel += 4;
189-
}
190-
}
191-
192-
if (r.x1 == (int)width && r.x2 == 0) {
193-
// The buffer is completely empty.
194-
r.x1 = r.y1 = r.x2 = r.y2 = 0;
195-
} else {
196-
r.x1 = std::max(0, r.x1);
197-
r.y1 = std::max(0, r.y1);
198-
r.x2 = std::min(r.x2 + 1, (int)width);
199-
r.y2 = std::min(r.y2 + 1, (int)height);
200-
}
201-
202-
return r;
203-
}
204-
205170
void RendererAgg::clear()
206171
{
207172
//"clear the rendered buffer";

src/_backend_agg_wrapper.cpp

-12
Original file line numberDiff line numberDiff line change
@@ -526,17 +526,6 @@ PyRendererAgg_draw_gouraud_triangles(PyRendererAgg *self, PyObject *args, PyObje
526526
Py_RETURN_NONE;
527527
}
528528

529-
static PyObject *
530-
PyRendererAgg_get_content_extents(PyRendererAgg *self, PyObject *args, PyObject *kwds)
531-
{
532-
agg::rect_i extents;
533-
534-
CALL_CPP("get_content_extents", (extents = self->x->get_content_extents()));
535-
536-
return Py_BuildValue(
537-
"iiii", extents.x1, extents.y1, extents.x2 - extents.x1, extents.y2 - extents.y1);
538-
}
539-
540529
int PyRendererAgg_get_buffer(PyRendererAgg *self, Py_buffer *buf, int flags)
541530
{
542531
Py_INCREF(self);
@@ -627,7 +616,6 @@ static PyTypeObject *PyRendererAgg_init_type(PyObject *m, PyTypeObject *type)
627616
{"draw_gouraud_triangle", (PyCFunction)PyRendererAgg_draw_gouraud_triangle, METH_VARARGS, NULL},
628617
{"draw_gouraud_triangles", (PyCFunction)PyRendererAgg_draw_gouraud_triangles, METH_VARARGS, NULL},
629618

630-
{"get_content_extents", (PyCFunction)PyRendererAgg_get_content_extents, METH_NOARGS, NULL},
631619
{"clear", (PyCFunction)PyRendererAgg_clear, METH_NOARGS, NULL},
632620

633621
{"copy_from_bbox", (PyCFunction)PyRendererAgg_copy_from_bbox, METH_VARARGS, NULL},

0 commit comments

Comments
 (0)