Skip to content
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

Add Surface.premul_alpha_ip() #2899

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion buildconfig/stubs/pygame/surface.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,6 @@ class Surface:
def get_view(self, kind: _ViewKind = "2", /) -> BufferProxy: ...
def get_buffer(self) -> BufferProxy: ...
def get_blendmode(self) -> int: ...
def premul_alpha(self) -> Surface: ...
def premul_alpha(self, in_place: bool) -> Surface: ...
MyreMylar marked this conversation as resolved.
Show resolved Hide resolved

SurfaceType = Surface
5 changes: 4 additions & 1 deletion docs/reST/ref/surface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -998,13 +998,16 @@
.. method:: premul_alpha

| :sl:`returns a copy of the surface with the RGB channels pre-multiplied by the alpha channel.`
itzpr3d4t0r marked this conversation as resolved.
Show resolved Hide resolved
| :sg:`premul_alpha() -> Surface`
| :sg:`premul_alpha(in_place=False) -> Surface`

Returns a copy of the initial surface with the red, green and blue color channels multiplied
by the alpha channel. This is intended to make it easier to work with the BLEND_PREMULTIPLED
blend mode flag of the blit() method. Surfaces which have called this method will only look
correct after blitting if the BLEND_PREMULTIPLED special flag is used.

If in_place is True, the operation is done in place and the surface is returned. If in_place is False,
a new surface is returned and the original surface is left unchanged.

itzpr3d4t0r marked this conversation as resolved.
Show resolved Hide resolved
It is worth noting that after calling this method, methods that return the color of a pixel
such as get_at() will return the alpha multiplied color values. It is not possible to fully
reverse an alpha multiplication of the colors in a surface as integer color channel data
Expand Down
2 changes: 1 addition & 1 deletion src_c/doc/surface_doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
#define DOC_SURFACE_GETVIEW "get_view(kind='2', /) -> BufferProxy\nreturn a buffer view of the Surface's pixels."
#define DOC_SURFACE_GETBUFFER "get_buffer() -> BufferProxy\nacquires a buffer object for the pixels of the Surface."
#define DOC_SURFACE_PIXELSADDRESS "_pixels_address -> int\npixel buffer address"
#define DOC_SURFACE_PREMULALPHA "premul_alpha() -> Surface\nreturns a copy of the surface with the RGB channels pre-multiplied by the alpha channel."
#define DOC_SURFACE_PREMULALPHA "premul_alpha(in_place=False) -> Surface\nreturns a copy of the surface with the RGB channels pre-multiplied by the alpha channel."
#define DOC_SURFACE_WIDTH "width -> int\nSurface width in pixels (read-only)"
#define DOC_SURFACE_HEIGHT "height -> int\nSurface height in pixels (read-only)"
#define DOC_SURFACE_SIZE "height -> tuple[int, int]\nSurface size in pixels (read-only)"
42 changes: 30 additions & 12 deletions src_c/surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,8 @@ surf_get_bounding_rect(PyObject *self, PyObject *args, PyObject *kwargs);
static PyObject *
surf_get_pixels_address(PyObject *self, PyObject *closure);
static PyObject *
surf_premul_alpha(pgSurfaceObject *self, PyObject *args);
surf_premul_alpha(pgSurfaceObject *self, PyObject *const *args,
Py_ssize_t nargs);
static int
_view_kind(PyObject *obj, void *view_kind_vptr);
static int
Expand Down Expand Up @@ -351,7 +352,7 @@ static struct PyMethodDef surface_methods[] = {
METH_VARARGS | METH_KEYWORDS, DOC_SURFACE_GETBOUNDINGRECT},
{"get_view", surf_get_view, METH_VARARGS, DOC_SURFACE_GETVIEW},
{"get_buffer", surf_get_buffer, METH_NOARGS, DOC_SURFACE_GETBUFFER},
{"premul_alpha", (PyCFunction)surf_premul_alpha, METH_NOARGS,
{"premul_alpha", (PyCFunction)surf_premul_alpha, METH_FASTCALL,
DOC_SURFACE_PREMULALPHA},

{NULL, NULL, 0, NULL}};
Expand Down Expand Up @@ -3166,32 +3167,49 @@ surf_get_buffer(PyObject *self, PyObject *_null)
}

static PyObject *
surf_premul_alpha(pgSurfaceObject *self, PyObject *_null)
surf_premul_alpha(pgSurfaceObject *self, PyObject *const *args,
Py_ssize_t nargs)
{
SDL_Surface *surf = pgSurface_AsSurface(self);
SURF_INIT_CHECK(surf)
PyObject *final;
SDL_Surface *newsurf;
int in_place = 0;

SURF_INIT_CHECK(surf)
if (nargs == 1) {
in_place = PyObject_IsTrue(args[0]);
if (in_place == -1)
return NULL;
}
else if (nargs > 1) {
return RAISE(PyExc_TypeError,
"premul_alpha() takes at most 1 argument");
}

pgSurface_Prep(self);
// Make a copy of the surface first
newsurf = PG_ConvertSurface(surf, surf->format);

SDL_Surface *newsurf =
in_place ? surf : PG_ConvertSurface(surf, surf->format);

if ((surf->w > 0 && surf->h > 0)) {
// If the surface has no pixels we don't need to premul
// just return the copy.
if (premul_surf_color_by_alpha(surf, newsurf) != 0) {
return RAISE(PyExc_ValueError,
"source surface to be alpha pre-multiplied must have "
"alpha channel");
}
}

pgSurface_Unprep(self);

final = surf_subtype_new(Py_TYPE(self), newsurf, 1);
if (!final)
SDL_FreeSurface(newsurf);
if (in_place) {
Py_INCREF(self);
final = (PyObject *)self;
}
else {
final = surf_subtype_new(Py_TYPE(self), newsurf, 1);
if (!final)
SDL_FreeSurface(newsurf);
}

return final;
}

Expand Down
Loading