Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b9b02f1

Browse files
authored
Merge pull request #11845 from anntzer/qt4formatargb32
Use Format_ARGB32_Premultiplied instead of RGBA8888 for Qt backends.
2 parents 7dc526e + 1acad5c commit b9b02f1

File tree

3 files changed

+49
-47
lines changed

3 files changed

+49
-47
lines changed

lib/matplotlib/backends/backend_cairo.py

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -42,48 +42,6 @@
4242
from matplotlib.transforms import Affine2D
4343

4444

45-
# Cairo's image buffers are premultiplied ARGB32,
46-
# Matplotlib's are unmultiplied RGBA8888.
47-
48-
49-
def _premultiplied_argb32_to_unmultiplied_rgba8888(buf):
50-
"""
51-
Convert a premultiplied ARGB32 buffer to an unmultiplied RGBA8888 buffer.
52-
"""
53-
rgba = np.take( # .take() ensures C-contiguity of the result.
54-
buf,
55-
[2, 1, 0, 3] if sys.byteorder == "little" else [1, 2, 3, 0], axis=2)
56-
rgb = rgba[..., :-1]
57-
alpha = rgba[..., -1]
58-
# Un-premultiply alpha. The formula is the same as in cairo-png.c.
59-
mask = alpha != 0
60-
for channel in np.rollaxis(rgb, -1):
61-
channel[mask] = (
62-
(channel[mask].astype(int) * 255 + alpha[mask] // 2)
63-
// alpha[mask])
64-
return rgba
65-
66-
67-
def _unmultipled_rgba8888_to_premultiplied_argb32(rgba8888):
68-
"""
69-
Convert an unmultiplied RGBA8888 buffer to a premultiplied ARGB32 buffer.
70-
"""
71-
if sys.byteorder == "little":
72-
argb32 = np.take(rgba8888, [2, 1, 0, 3], axis=2)
73-
rgb24 = argb32[..., :-1]
74-
alpha8 = argb32[..., -1:]
75-
else:
76-
argb32 = np.take(rgba8888, [3, 0, 1, 2], axis=2)
77-
alpha8 = argb32[..., :1]
78-
rgb24 = argb32[..., 1:]
79-
# Only bother premultiplying when the alpha channel is not fully opaque,
80-
# as the cost is not negligible. The unsafe cast is needed to do the
81-
# multiplication in-place in an integer buffer.
82-
if alpha8.min() != 0xff:
83-
np.multiply(rgb24, alpha8 / 0xff, out=rgb24, casting="unsafe")
84-
return argb32
85-
86-
8745
if cairo.__name__ == "cairocffi":
8846
# Convert a pycairo context to a cairocffi one.
8947
def _to_context(ctx):
@@ -380,7 +338,7 @@ def _draw_paths():
380338
_draw_paths()
381339

382340
def draw_image(self, gc, x, y, im):
383-
im = _unmultipled_rgba8888_to_premultiplied_argb32(im[::-1])
341+
im = cbook._unmultipled_rgba8888_to_premultiplied_argb32(im[::-1])
384342
surface = cairo.ImageSurface.create_for_data(
385343
im.ravel().data, cairo.FORMAT_ARGB32,
386344
im.shape[1], im.shape[0], im.shape[1] * 4)
@@ -586,7 +544,7 @@ def print_png(self, fobj, *args, **kwargs):
586544
def print_rgba(self, fobj, *args, **kwargs):
587545
width, height = self.get_width_height()
588546
buf = self._get_printed_image_surface().get_data()
589-
fobj.write(_premultiplied_argb32_to_unmultiplied_rgba8888(
547+
fobj.write(cbook._premultiplied_argb32_to_unmultiplied_rgba8888(
590548
np.asarray(buf).reshape((width, height, 4))))
591549

592550
print_raw = print_rgba

lib/matplotlib/backends/backend_qt5agg.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from matplotlib.transforms import Bbox
88

9+
from .. import cbook
910
from .backend_agg import FigureCanvasAgg
1011
from .backend_qt5 import (
1112
QtCore, QtGui, QtWidgets, _BackendQT5, FigureCanvasQT, FigureManagerQT,
@@ -52,9 +53,10 @@ def paintEvent(self, event):
5253
[[left, self.renderer.height - (top + height * self._dpi_ratio)],
5354
[left + width * self._dpi_ratio, self.renderer.height - top]])
5455
reg = self.copy_from_bbox(bbox)
55-
buf = memoryview(reg)
56-
qimage = QtGui.QImage(
57-
buf, buf.shape[1], buf.shape[0], QtGui.QImage.Format_RGBA8888)
56+
buf = cbook._unmultipled_rgba8888_to_premultiplied_argb32(
57+
memoryview(reg))
58+
qimage = QtGui.QImage(buf, buf.shape[1], buf.shape[0],
59+
QtGui.QImage.Format_ARGB32_Premultiplied)
5860
if hasattr(qimage, 'setDevicePixelRatio'):
5961
# Not available on Qt4 or some older Qt5.
6062
qimage.setDevicePixelRatio(self._dpi_ratio)

lib/matplotlib/cbook/__init__.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,3 +2033,45 @@ def add(self, key):
20332033

20342034
def discard(self, key):
20352035
self._od.pop(key, None)
2036+
2037+
2038+
# Agg's buffers are unmultiplied RGBA8888, which neither PyQt4 nor cairo
2039+
# support; however, both do support premultiplied ARGB32.
2040+
2041+
2042+
def _premultiplied_argb32_to_unmultiplied_rgba8888(buf):
2043+
"""
2044+
Convert a premultiplied ARGB32 buffer to an unmultiplied RGBA8888 buffer.
2045+
"""
2046+
rgba = np.take( # .take() ensures C-contiguity of the result.
2047+
buf,
2048+
[2, 1, 0, 3] if sys.byteorder == "little" else [1, 2, 3, 0], axis=2)
2049+
rgb = rgba[..., :-1]
2050+
alpha = rgba[..., -1]
2051+
# Un-premultiply alpha. The formula is the same as in cairo-png.c.
2052+
mask = alpha != 0
2053+
for channel in np.rollaxis(rgb, -1):
2054+
channel[mask] = (
2055+
(channel[mask].astype(int) * 255 + alpha[mask] // 2)
2056+
// alpha[mask])
2057+
return rgba
2058+
2059+
2060+
def _unmultipled_rgba8888_to_premultiplied_argb32(rgba8888):
2061+
"""
2062+
Convert an unmultiplied RGBA8888 buffer to a premultiplied ARGB32 buffer.
2063+
"""
2064+
if sys.byteorder == "little":
2065+
argb32 = np.take(rgba8888, [2, 1, 0, 3], axis=2)
2066+
rgb24 = argb32[..., :-1]
2067+
alpha8 = argb32[..., -1:]
2068+
else:
2069+
argb32 = np.take(rgba8888, [3, 0, 1, 2], axis=2)
2070+
alpha8 = argb32[..., :1]
2071+
rgb24 = argb32[..., 1:]
2072+
# Only bother premultiplying when the alpha channel is not fully opaque,
2073+
# as the cost is not negligible. The unsafe cast is needed to do the
2074+
# multiplication in-place in an integer buffer.
2075+
if alpha8.min() != 0xff:
2076+
np.multiply(rgb24, alpha8 / 0xff, out=rgb24, casting="unsafe")
2077+
return argb32

0 commit comments

Comments
 (0)