diff --git a/lib/matplotlib/backends/backend_gtk3agg.py b/lib/matplotlib/backends/backend_gtk3agg.py index f54849cf049c..c7b79c75a109 100644 --- a/lib/matplotlib/backends/backend_gtk3agg.py +++ b/lib/matplotlib/backends/backend_gtk3agg.py @@ -1,6 +1,8 @@ -import numpy as np +import sys import warnings +import numpy as np + from . import backend_agg, backend_cairo, backend_gtk3 from ._gtk3_compat import gi from .backend_cairo import cairo @@ -31,7 +33,7 @@ def _render_figure(self, width, height): backend_agg.FigureCanvasAgg.draw(self) def on_draw_event(self, widget, ctx): - """ GtkDrawable draw event, like expose_event in GTK 2.X + """GtkDrawable draw event, like expose_event in GTK 2.X. """ allocation = self.get_allocation() w, h = allocation.width, allocation.height @@ -45,17 +47,29 @@ def on_draw_event(self, widget, ctx): ctx = backend_cairo._to_context(ctx) for bbox in bbox_queue: - area = self.copy_from_bbox(bbox) - buf = np.fromstring(area.to_string_argb(), dtype='uint8') - x = int(bbox.x0) y = h - int(bbox.y1) width = int(bbox.x1) - int(bbox.x0) height = int(bbox.y1) - int(bbox.y0) + buf = (np.fromstring(self.copy_from_bbox(bbox).to_string_argb(), + dtype='uint8') + .reshape((width, height, 4))) + # cairo wants premultiplied alpha. Only bother doing the + # conversion when the alpha channel is not fully opaque, as the + # cost is not negligible. (The unsafe cast is needed to do the + # multiplication in-place in an integer buffer.) + if sys.byteorder == "little": + rgb24 = buf[..., :-1] + alpha8 = buf[..., -1:] + else: + alpha8 = buf[..., :1] + rgb24 = buf[..., 1:] + if alpha8.min() != 0xff: + np.multiply(rgb24, alpha8 / 0xff, out=rgb24, casting="unsafe") + image = cairo.ImageSurface.create_for_data( - buf.ravel().data, cairo.FORMAT_ARGB32, - width, height, width * 4) + buf.ravel().data, cairo.FORMAT_ARGB32, width, height) ctx.set_source_surface(image, x, y) ctx.paint()