Skip to content

Commit 864c9a8

Browse files
committed
Add print_rgba to backend_cairo.
This ensures that when a cairo-based backend is active, animations also get saved using backend_cairo, rather than falling back on backend_agg.
1 parent fc73593 commit 864c9a8

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

lib/matplotlib/backends/backend_cairo.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@
4747
from matplotlib.font_manager import ttfFontProperty
4848

4949

50+
def _premultiplied_argb32_to_unmultiplied_rgba8888(buf):
51+
"""
52+
Convert a premultiplied ARGB32 buffer to an unmultiplied RGBA8888 buffer.
53+
54+
Cairo uses the former format, Matplotlib the latter.
55+
"""
56+
rgba = np.take( # .take() ensures C-contiguity of the result.
57+
buf,
58+
[2, 1, 0, 3] if sys.byteorder == "little" else [1, 2, 3, 0], axis=2)
59+
rgb = rgba[..., :-1]
60+
alpha = rgba[..., -1]
61+
# Un-premultiply alpha. The formula is the same as in cairo-png.c.
62+
mask = alpha != 0
63+
for channel in np.rollaxis(rgb, -1):
64+
channel[mask] = (
65+
(channel[mask].astype(int) * 255 + alpha[mask] // 2)
66+
// alpha[mask])
67+
return rgba
68+
69+
5070
class ArrayWrapper:
5171
"""Thin wrapper around numpy ndarray to expose the interface
5272
expected by cairocffi. Basically replicates the
@@ -436,15 +456,24 @@ class FigureCanvasCairo(FigureCanvasBase):
436456
supports_blit = False
437457

438458
def print_png(self, fobj, *args, **kwargs):
459+
self._get_printed_image_surface().write_to_png(fobj)
460+
461+
def print_rgba(self, fobj, *args, **kwargs):
439462
width, height = self.get_width_height()
463+
buf = self._get_printed_image_surface().get_data()
464+
fobj.write(_premultiplied_argb32_to_unmultiplied_rgba8888(
465+
np.asarray(buf).reshape((width, height, 4))))
466+
467+
print_raw = print_rgba
440468

469+
def _get_printed_image_surface(self):
470+
width, height = self.get_width_height()
441471
renderer = RendererCairo(self.figure.dpi)
442472
renderer.set_width_height(width, height)
443473
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
444474
renderer.set_ctx_from_surface(surface)
445-
446475
self.figure.draw(renderer)
447-
surface.write_to_png(fobj)
476+
return surface
448477

449478
def print_pdf(self, fobj, *args, **kwargs):
450479
return self._save(fobj, 'pdf', *args, **kwargs)

0 commit comments

Comments
 (0)