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

Skip to content

Commit 5e58ef0

Browse files
committed
Fix bug with an isolated blend group in Cairo using the group blend mode knockout or clear
1 parent ff01737 commit 5e58ef0

4 files changed

Lines changed: 34 additions & 6 deletions

File tree

lib/matplotlib/backends/backend_cairo.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,26 @@ def close_blend_group(self):
378378
ctx.save()
379379
self.gc.set_blend_mode(group_state.blend_mode)
380380
ctx.set_source(group)
381-
if group_state.alpha != 1:
382-
ctx.paint_with_alpha(group_state.alpha)
381+
382+
# For these two Porter-Duff compositing operators, we need to mask out fully
383+
# transparent pixels, otherwise those pixels will override the backdrop
384+
if group_state.blend_mode in {'knockout', 'clear'}:
385+
# Extract the 8-bit alpha channel
386+
mask_surface = ctx.get_target().create_similar_image(
387+
cairo.FORMAT_A8, self.width, self.height)
388+
mask_ctx = cairo.Context(mask_surface)
389+
mask_ctx.set_source(group)
390+
mask_ctx.paint()
391+
mask_surface.flush()
392+
393+
# Pixels that are not fully transparent are painted with the group alpha
394+
mask_buf = np.asarray(mask_surface.get_data())
395+
mask_buf[mask_buf > 0] = 255 * group_state.alpha + 0.5
396+
mask_pattern = cairo.SurfacePattern(mask_surface)
397+
ctx.mask(mask_pattern)
383398
else:
384-
ctx.paint()
399+
ctx.paint_with_alpha(group_state.alpha)
400+
385401
ctx.restore()
386402

387403

1.43 KB
Loading
1.69 KB
Loading

lib/matplotlib/tests/test_backends_rendering.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def draw(self, renderer):
9292
renderer.close_blend_group()
9393

9494

95-
def plot_blend_group_types(rasterize=False):
95+
def plot_blend_group_types(rasterize=False, porterduff=False):
9696
# Rows: top row is non-isolated, bottom row is isolated
9797
# Columns: left column is non-knockout, right column is knockout
9898
fig, axs = plt.subplots(2, 2, figsize=(3, 3), dpi=80, layout='constrained')
@@ -128,6 +128,18 @@ def plot_blend_group_types(rasterize=False):
128128
gray = Circle((0, 0), 0.1, fc='gray', zorder=0)
129129
axs[i, j].add_artist(gray)
130130

131+
# For backends that support the Porter-Duff compositing operators, additionally
132+
# test 'knockout' and 'clear' as the blend mode for an isolated group
133+
if porterduff:
134+
for x, group_blend_mode, group_alpha in [(-0.6, 'knockout', 1),
135+
(-0.2, 'knockout', 0.6),
136+
(0.2, 'clear', 0.6),
137+
(0.6, 'clear', 1)]:
138+
circle = Circle((x, -0.8), 0.15, fc='k', alpha=0.75)
139+
group = ArtistGroup([circle], group_blend_mode=group_blend_mode,
140+
group_alpha=group_alpha)
141+
axs[1, 0].add_artist(group)
142+
131143

132144
@image_comparison(['blend_modes_agg.png'], style='mpl20')
133145
def test_blend_modes_agg():
@@ -183,7 +195,7 @@ def test_blend_groups_agg():
183195
# The top-right panel (knockout but not isolated) is not supported, so will be
184196
# rendered like the top-left panel (neither knockout nor isolated)
185197

186-
plot_blend_group_types()
198+
plot_blend_group_types(porterduff=True)
187199

188200

189201
@pytest.mark.backend('cairo')
@@ -192,7 +204,7 @@ def test_blend_groups_cairo():
192204
# The top-right panel (knockout but not isolated) is not supported, so will be
193205
# rendered like the top-left panel (neither knockout nor isolated)
194206

195-
plot_blend_group_types()
207+
plot_blend_group_types(porterduff=True)
196208

197209

198210
@image_comparison(['blend_groups_svg.svg'], style='mpl20')

0 commit comments

Comments
 (0)