Skip to content

Commit 3761775

Browse files
Add Surface.premul_alpha_ip() (#2899)
* Added Surface.premul_alpha_ip() --------- Co-authored-by: Dan Lawrence <[email protected]>
1 parent 198bbcc commit 3761775

File tree

5 files changed

+116
-0
lines changed

5 files changed

+116
-0
lines changed

buildconfig/stubs/pygame/surface.pyi

+1
Original file line numberDiff line numberDiff line change
@@ -162,5 +162,6 @@ class Surface:
162162
def get_buffer(self) -> BufferProxy: ...
163163
def get_blendmode(self) -> int: ...
164164
def premul_alpha(self) -> Surface: ...
165+
def premul_alpha_ip(self) -> Surface: ...
165166

166167
SurfaceType = Surface

docs/reST/ref/surface.rst

+17
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,23 @@
10411041

10421042
.. ## Surface.premul_alpha ##
10431043
1044+
.. method:: premul_alpha_ip
1045+
1046+
| :sl:`multiplies the RGB channels by the surface alpha channel.`
1047+
| :sg:`premul_alpha_ip() -> Surface`
1048+
1049+
Multiplies the RGB channels of the surface by the alpha channel in place and returns the surface.
1050+
1051+
Surfaces without an alpha channel cannot use this method and will return an error if you use
1052+
it on them. It is best used on 32 bit surfaces (the default on most platforms) as the blitting
1053+
on these surfaces can be accelerated by SIMD versions of the pre-multiplied blitter.
1054+
1055+
Refer to the :meth:`premul_alpha` method for more information.
1056+
1057+
.. versionadded:: 2.5.1
1058+
1059+
.. ## Surface.premul_alpha_ip ##
1060+
10441061
.. attribute:: width
10451062

10461063
| :sl:`Surface width in pixels (read-only)`

src_c/doc/surface_doc.h

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#define DOC_SURFACE_GETBUFFER "get_buffer() -> BufferProxy\nacquires a buffer object for the pixels of the Surface."
5353
#define DOC_SURFACE_PIXELSADDRESS "_pixels_address -> int\npixel buffer address"
5454
#define DOC_SURFACE_PREMULALPHA "premul_alpha() -> Surface\nreturns a copy of the surface with the RGB channels pre-multiplied by the alpha channel."
55+
#define DOC_SURFACE_PREMULALPHAIP "premul_alpha_ip() -> Surface\nmultiplies the RGB channels by the surface alpha channel."
5556
#define DOC_SURFACE_WIDTH "width -> int\nSurface width in pixels (read-only)"
5657
#define DOC_SURFACE_HEIGHT "height -> int\nSurface height in pixels (read-only)"
5758
#define DOC_SURFACE_SIZE "height -> tuple[int, int]\nSurface size in pixels (read-only)"

src_c/surface.c

+27
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ static PyObject *
194194
surf_get_pixels_address(PyObject *self, PyObject *closure);
195195
static PyObject *
196196
surf_premul_alpha(pgSurfaceObject *self, PyObject *args);
197+
static PyObject *
198+
surf_premul_alpha_ip(pgSurfaceObject *self, PyObject *args);
197199
static int
198200
_view_kind(PyObject *obj, void *view_kind_vptr);
199201
static int
@@ -318,6 +320,8 @@ static struct PyMethodDef surface_methods[] = {
318320
{"get_buffer", surf_get_buffer, METH_NOARGS, DOC_SURFACE_GETBUFFER},
319321
{"premul_alpha", (PyCFunction)surf_premul_alpha, METH_NOARGS,
320322
DOC_SURFACE_PREMULALPHA},
323+
{"premul_alpha_ip", (PyCFunction)surf_premul_alpha_ip, METH_NOARGS,
324+
DOC_SURFACE_PREMULALPHAIP},
321325

322326
{NULL, NULL, 0, NULL}};
323327

@@ -3124,6 +3128,29 @@ surf_premul_alpha(pgSurfaceObject *self, PyObject *_null)
31243128
return final;
31253129
}
31263130

3131+
static PyObject *
3132+
surf_premul_alpha_ip(pgSurfaceObject *self, PyObject *_null)
3133+
{
3134+
SDL_Surface *surf = pgSurface_AsSurface(self);
3135+
SURF_INIT_CHECK(surf)
3136+
3137+
if (!surf->w || !surf->h)
3138+
Py_RETURN_NONE;
3139+
3140+
pgSurface_Prep(self);
3141+
3142+
if (premul_surf_color_by_alpha(surf, surf) != 0) {
3143+
return RAISE(PyExc_ValueError,
3144+
"source surface to be alpha pre-multiplied must have "
3145+
"alpha channel");
3146+
}
3147+
3148+
pgSurface_Unprep(self);
3149+
3150+
Py_INCREF(self);
3151+
return (PyObject *)self;
3152+
}
3153+
31273154
static int
31283155
_get_buffer_0D(PyObject *obj, Py_buffer *view_p, int flags)
31293156
{

test/surface_test.py

+70
Original file line numberDiff line numberDiff line change
@@ -4038,6 +4038,76 @@ def test_surface_premul_alpha(self):
40384038
),
40394039
)
40404040

4041+
def test_surface_premul_alpha_ip(self):
4042+
"""Ensure that .premul_alpha_ip() works correctly"""
4043+
4044+
# basic functionality at valid bit depths - 32, 16 & 8
4045+
s1 = pygame.Surface((100, 100), pygame.SRCALPHA, 32)
4046+
s1.fill(pygame.Color(255, 255, 255, 100))
4047+
s1.premul_alpha_ip()
4048+
s1_alpha = s1
4049+
self.assertEqual(s1_alpha.get_at((50, 50)), pygame.Color(100, 100, 100, 100))
4050+
4051+
# 16-bit color has less precision
4052+
s2 = pygame.Surface((100, 100), pygame.SRCALPHA, 16)
4053+
s2.fill(
4054+
pygame.Color(
4055+
int(15 / 15 * 255),
4056+
int(15 / 15 * 255),
4057+
int(15 / 15 * 255),
4058+
int(10 / 15 * 255),
4059+
)
4060+
)
4061+
s2.premul_alpha_ip()
4062+
s2_alpha = s2
4063+
self.assertEqual(
4064+
s2_alpha.get_at((50, 50)),
4065+
pygame.Color(
4066+
int(10 / 15 * 255),
4067+
int(10 / 15 * 255),
4068+
int(10 / 15 * 255),
4069+
int(10 / 15 * 255),
4070+
),
4071+
)
4072+
4073+
# invalid surface - we need alpha to pre-multiply
4074+
invalid_surf = pygame.Surface((100, 100), 0, 32)
4075+
invalid_surf.fill(pygame.Color(255, 255, 255, 100))
4076+
with self.assertRaises(ValueError):
4077+
invalid_surf.premul_alpha_ip()
4078+
4079+
# churn a bunch of values
4080+
test_colors = [
4081+
(200, 30, 74),
4082+
(76, 83, 24),
4083+
(184, 21, 6),
4084+
(74, 4, 74),
4085+
(76, 83, 24),
4086+
(184, 21, 234),
4087+
(160, 30, 74),
4088+
(96, 147, 204),
4089+
(198, 201, 60),
4090+
(132, 89, 74),
4091+
(245, 9, 224),
4092+
(184, 112, 6),
4093+
]
4094+
4095+
for r, g, b in test_colors:
4096+
for a in range(255):
4097+
with self.subTest(r=r, g=g, b=b, a=a):
4098+
surf = pygame.Surface((10, 10), pygame.SRCALPHA, 32)
4099+
surf.fill(pygame.Color(r, g, b, a))
4100+
surf.premul_alpha_ip()
4101+
self.assertEqual(
4102+
surf.get_at((5, 5)),
4103+
Color(
4104+
((r + 1) * a) >> 8,
4105+
((g + 1) * a) >> 8,
4106+
((b + 1) * a) >> 8,
4107+
a,
4108+
),
4109+
)
4110+
40414111

40424112
class SurfaceSelfBlitTest(unittest.TestCase):
40434113
"""Blit to self tests.

0 commit comments

Comments
 (0)