-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix gtk3agg alpha channel. #10297
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
Fix gtk3agg alpha channel. #10297
Conversation
Is there a test for this? |
Basically run the example code yourself and observe the background color of the figure as explained above... (not sure it can be automated in any reasonable way) |
if sys.byteorder == "little": | ||
alpha = buf[..., -1:] | ||
if alpha.min() != 0xff: | ||
buf = (np.dstack([buf[..., :3] * (alpha / 0xff), alpha]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to make a copy? Isn't buf
an independent thing, so can you do an in-place multiply?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was a bit more tricky to write correctly but fixed it
9d62bb0
to
fd9da34
Compare
When I try out your example, I get an error: Traceback (most recent call last):
File "/home/elliott/code/matplotlib/lib/matplotlib/backends/backend_gtk3agg.py", line 76, in on_draw_event
buf.data, cairo.FORMAT_ARGB32, width, height)
File "/usr/lib/python3.6/site-packages/cairocffi/surfaces.py", line 660, in create_for_data
return cls(format, width, height, data, stride)
File "/usr/lib/python3.6/site-packages/cairocffi/surfaces.py", line 649, in __init__
% (length, stride * height))
ValueError: Got a 640 bytes buffer, needs at least 1228800. |
fd9da34
to
04e22f3
Compare
Ah, that's because I use pycairo (which actually works with py3 now...) rather than cairocffi. Ravel()ing the buffer before passing it to create_for_data fixes the problem and works for both pycairo and cairocffi, pushed that. |
Should we remove the warning then? |
Yup. Have another PR in the works for that. |
rebased |
The gtk3agg backend works by drawing the ARGB32 buffer (from Agg) onto a cairo context (passed by gtk3). However, cairo wants a *premultiplied* ARGB32 buffer (i.e., where 100% blue with 50% transparency is represented by (r=0%, g=0%, b=50%, a=50%) instead of (r=0%, g=0%, b=100%, a=50%), which we didn't do before. This is only apparent if the entire buffer contains some transparency, e.g. if the figure background is transparent. Consider e.g. under gtk3agg: from pylab import * rcParams["figure.facecolor"] = (0, 0, 0, 0) gca() show() Without the patch, the area surrounding the axes is white (because of the misinterpretation of premultiplied alpha). With the patch, it is (correctly) gray, which is the background color of the gtk widget. (Note that when running the example under qt5agg or tkagg, the situation is complicated by the fact that these backends themselves set the widget background color to white rather than gray.) As a comparison point, qt5agg builds the QImage using Format_ARGB32, instead of Format_ARB32_Premultiplied; i.e. Qt provides its own conversion from non-premultiplied to premultiplied. The premultiplication step involves allocating a full new buffer, so check whether there is actually any transparency before doing it.
The gtk3agg backend works by drawing the ARGB32 buffer (from Agg) onto a
cairo context (passed by gtk3). However, cairo wants a premultiplied
ARGB32 buffer (i.e., where 100% blue with 50% transparency is
represented by (r=0%, g=0%, b=50%, a=50%) instead of (r=0%, g=0%,
b=100%, a=50%), which we didn't do before.
This is only apparent if the entire buffer contains some transparency,
e.g. if the figure background is transparent. Consider e.g. under
gtk3agg:
Without the patch, the area surrounding the axes is white (because of
the misinterpretation of premultiplied alpha). With the patch, it is
(correctly) gray, which is the background color of the gtk widget.
(Note that when running the example under qt5agg or tkagg, the situation
is complicated by the fact that these backends themselves set the widget
background color to white rather than gray.)
As a comparison point, qt5agg builds the QImage using Format_ARGB32,
instead of Format_ARB32_Premultiplied; i.e. Qt provides its own
conversion from non-premultiplied to premultiplied.
The premultiplication step involves allocating a full new buffer, so
check whether there is actually any transparency before doing it.
PR Summary
PR Checklist