|
47 | 47 | from matplotlib.font_manager import ttfFontProperty
|
48 | 48 |
|
49 | 49 |
|
| 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 | + |
50 | 70 | class ArrayWrapper:
|
51 | 71 | """Thin wrapper around numpy ndarray to expose the interface
|
52 | 72 | expected by cairocffi. Basically replicates the
|
@@ -436,15 +456,24 @@ class FigureCanvasCairo(FigureCanvasBase):
|
436 | 456 | supports_blit = False
|
437 | 457 |
|
438 | 458 | 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): |
439 | 462 | 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 |
440 | 468 |
|
| 469 | + def _get_printed_image_surface(self): |
| 470 | + width, height = self.get_width_height() |
441 | 471 | renderer = RendererCairo(self.figure.dpi)
|
442 | 472 | renderer.set_width_height(width, height)
|
443 | 473 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
|
444 | 474 | renderer.set_ctx_from_surface(surface)
|
445 |
| - |
446 | 475 | self.figure.draw(renderer)
|
447 |
| - surface.write_to_png(fobj) |
| 476 | + return surface |
448 | 477 |
|
449 | 478 | def print_pdf(self, fobj, *args, **kwargs):
|
450 | 479 | return self._save(fobj, 'pdf', *args, **kwargs)
|
|
0 commit comments