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

Skip to content

Commit 78d3876

Browse files
committed
Fix bug with an isolated blend group in Cairo using the group blend mode knockout or clear
1 parent 0350707 commit 78d3876

4 files changed

Lines changed: 33 additions & 6 deletions

File tree

lib/matplotlib/backends/backend_cairo.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,25 @@ 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 # round to int
396+
ctx.mask_surface(mask_surface)
383397
else:
384-
ctx.paint()
398+
ctx.paint_with_alpha(group_state.alpha)
399+
385400
ctx.restore()
386401

387402

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
@@ -93,7 +93,7 @@ def draw(self, renderer):
9393
renderer.close_blend_group()
9494

9595

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

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

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

187-
plot_blend_group_types()
199+
plot_blend_group_types(porterduff=True)
188200

189201

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

196-
plot_blend_group_types()
208+
plot_blend_group_types(porterduff=True)
197209

198210

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

0 commit comments

Comments
 (0)