Skip to content

Add print_rgba to backend_cairo. #10828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 19, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions lib/matplotlib/backends/backend_cairo.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,26 @@
from matplotlib.font_manager import ttfFontProperty


def _premultiplied_argb32_to_unmultiplied_rgba8888(buf):
"""
Convert a premultiplied ARGB32 buffer to an unmultiplied RGBA8888 buffer.

Cairo uses the former format, Matplotlib the latter.
"""
rgba = np.take( # .take() ensures C-contiguity of the result.
buf,
[2, 1, 0, 3] if sys.byteorder == "little" else [1, 2, 3, 0], axis=2)
rgb = rgba[..., :-1]
alpha = rgba[..., -1]
# Un-premultiply alpha. The formula is the same as in cairo-png.c.
mask = alpha != 0
for channel in np.rollaxis(rgb, -1):
channel[mask] = (
(channel[mask].astype(int) * 255 + alpha[mask] // 2)
// alpha[mask])
return rgba


class ArrayWrapper:
"""Thin wrapper around numpy ndarray to expose the interface
expected by cairocffi. Basically replicates the
Expand Down Expand Up @@ -436,15 +456,24 @@ class FigureCanvasCairo(FigureCanvasBase):
supports_blit = False

def print_png(self, fobj, *args, **kwargs):
self._get_printed_image_surface().write_to_png(fobj)

def print_rgba(self, fobj, *args, **kwargs):
width, height = self.get_width_height()
buf = self._get_printed_image_surface().get_data()
fobj.write(_premultiplied_argb32_to_unmultiplied_rgba8888(
np.asarray(buf).reshape((width, height, 4))))

print_raw = print_rgba

def _get_printed_image_surface(self):
width, height = self.get_width_height()
renderer = RendererCairo(self.figure.dpi)
renderer.set_width_height(width, height)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
renderer.set_ctx_from_surface(surface)

self.figure.draw(renderer)
surface.write_to_png(fobj)
return surface

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