Skip to content

Commit 2d319fe

Browse files
authored
Merge pull request matplotlib#29776 from anntzer/ifpa
Filter images in premultiplied alpha mode.
2 parents c38f70a + 27cb5e3 commit 2d319fe

File tree

5 files changed

+27
-24
lines changed

5 files changed

+27
-24
lines changed

lib/matplotlib/image.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -496,37 +496,40 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
496496
out_alpha *= _resample(self, alpha, out_shape, t, resample=True)
497497
# mask and run through the norm
498498
resampled_masked = np.ma.masked_array(A_resampled, out_mask)
499-
output = self.norm(resampled_masked)
499+
res = self.norm(resampled_masked)
500500
else:
501501
if A.ndim == 2: # interpolation_stage = 'rgba'
502502
self.norm.autoscale_None(A)
503503
A = self.to_rgba(A)
504+
if A.dtype == np.uint8:
505+
# uint8 is too imprecise for premultiplied alpha roundtrips.
506+
A = np.divide(A, 0xff, dtype=np.float32)
504507
alpha = self.get_alpha()
508+
post_apply_alpha = False
505509
if alpha is None: # alpha parameter not specified
506510
if A.shape[2] == 3: # image has no alpha channel
507-
output_alpha = 255 if A.dtype == np.uint8 else 1.0
508-
else:
509-
output_alpha = _resample( # resample alpha channel
510-
self, A[..., 3], out_shape, t)
511-
output = _resample( # resample rgb channels
512-
self, _rgb_to_rgba(A[..., :3]), out_shape, t)
511+
A = np.dstack([A, np.ones(A.shape[:2])])
513512
elif np.ndim(alpha) > 0: # Array alpha
514513
# user-specified array alpha overrides the existing alpha channel
515-
output_alpha = _resample(self, alpha, out_shape, t)
516-
output = _resample(
517-
self, _rgb_to_rgba(A[..., :3]), out_shape, t)
514+
A = np.dstack([A[..., :3], alpha])
518515
else: # Scalar alpha
519516
if A.shape[2] == 3: # broadcast scalar alpha
520-
output_alpha = (255 * alpha) if A.dtype == np.uint8 else alpha
517+
A = np.dstack([A, np.full(A.shape[:2], alpha, np.float32)])
521518
else: # or apply scalar alpha to existing alpha channel
522-
output_alpha = _resample(self, A[..., 3], out_shape, t) * alpha
523-
output = _resample(
524-
self, _rgb_to_rgba(A[..., :3]), out_shape, t)
525-
output[..., 3] = output_alpha # recombine rgb and alpha
526-
527-
# output is now either a 2D array of normed (int or float) data
519+
post_apply_alpha = True
520+
# Resample in premultiplied alpha space. (TODO: Consider
521+
# implementing premultiplied-space resampling in
522+
# span_image_resample_rgba_affine::generate?)
523+
A[..., :3] *= A[..., 3:]
524+
res = _resample(self, A, out_shape, t)
525+
np.divide(res[..., :3], res[..., 3:], out=res[..., :3],
526+
where=res[..., 3:] != 0)
527+
if post_apply_alpha:
528+
res[..., 3] *= alpha
529+
530+
# res is now either a 2D array of normed (int or float) data
528531
# or an RGBA array of re-sampled input
529-
output = self.to_rgba(output, bytes=True, norm=False)
532+
output = self.to_rgba(res, bytes=True, norm=False)
530533
# output is now a correctly sized RGBA array of uint8
531534

532535
# Apply alpha *after* if the input was greyscale without a mask
Loading
Loading

lib/matplotlib/tests/test_image.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,15 @@ def test_image_alpha():
260260
def test_imshow_alpha(fig_test, fig_ref):
261261
np.random.seed(19680801)
262262

263-
rgbf = np.random.rand(6, 6, 3)
263+
rgbf = np.random.rand(6, 6, 3).astype(np.float32)
264264
rgbu = np.uint8(rgbf * 255)
265265
((ax0, ax1), (ax2, ax3)) = fig_test.subplots(2, 2)
266266
ax0.imshow(rgbf, alpha=0.5)
267267
ax1.imshow(rgbf, alpha=0.75)
268-
ax2.imshow(rgbu, alpha=0.5)
269-
ax3.imshow(rgbu, alpha=0.75)
268+
ax2.imshow(rgbu, alpha=127/255)
269+
ax3.imshow(rgbu, alpha=191/255)
270270

271-
rgbaf = np.concatenate((rgbf, np.ones((6, 6, 1))), axis=2)
271+
rgbaf = np.concatenate((rgbf, np.ones((6, 6, 1))), axis=2).astype(np.float32)
272272
rgbau = np.concatenate((rgbu, np.full((6, 6, 1), 255, np.uint8)), axis=2)
273273
((ax0, ax1), (ax2, ax3)) = fig_ref.subplots(2, 2)
274274
rgbaf[:, :, 3] = 0.5
@@ -514,7 +514,7 @@ def test_image_composite_background():
514514
ax.set_xlim([0, 12])
515515

516516

517-
@image_comparison(['image_composite_alpha'], remove_text=True)
517+
@image_comparison(['image_composite_alpha'], remove_text=True, tol=0.07)
518518
def test_image_composite_alpha():
519519
"""
520520
Tests that the alpha value is recognized and correctly applied in the

lib/matplotlib/tests/test_png.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from matplotlib import cm, pyplot as plt
88

99

10-
@image_comparison(['pngsuite.png'], tol=0.04)
10+
@image_comparison(['pngsuite.png'], tol=0.09)
1111
def test_pngsuite():
1212
files = sorted(
1313
(Path(__file__).parent / "baseline_images/pngsuite").glob("basn*.png"))

0 commit comments

Comments
 (0)