Skip to content

Commit 492bd22

Browse files
committed
added pygame.transform.pixelate
1 parent 04f4ad6 commit 492bd22

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

buildconfig/stubs/pygame/transform.pyi

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,3 +459,26 @@ def hsl(
459459
460460
.. versionadded:: 2.5.0
461461
"""
462+
463+
def pixelate(
464+
surface: Surface,
465+
pixel_size: int,
466+
dest_surface: Optional[Surface] = None
467+
) -> Surface:
468+
"""Returns a pixelated version of the original surface.
469+
470+
``pixel_size`` is an integer describing how large you want the pixels in the final pixelated image to be.
471+
An optional destination surface can be passed which is faster than creating a new Surface. This destination
472+
surface must have the same dimensions (width, height) and smae depth as the source surface.
473+
474+
:param pygame.Surface surface: the surface to pixelate.
475+
476+
:param int pixel_size: how large the pixels in the pixelated image should be.
477+
478+
:param pygame.Surface dest_surface: An optional destination surface to store the pixelated image.
479+
If provided, it should have the same dimensions and depth as the source surface.
480+
481+
:returns: A new surface that's been pixelated.
482+
483+
..versionadded:: 2.5.5
484+
"""

src_c/transform.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4225,6 +4225,116 @@ surf_invert(PyObject *self, PyObject *args, PyObject *kwargs)
42254225
return (PyObject *)pgSurface_New(newsurf);
42264226
}
42274227

4228+
SDL_Surface *
4229+
pixelate(pgSurfaceObject *srcobj, pgSurfaceObject *dstobj, int pixel_size)
4230+
{
4231+
SDL_Surface *src = pgSurface_AsSurface(srcobj);
4232+
SDL_Surface *newsurf;
4233+
4234+
if (!dstobj) {
4235+
newsurf = newsurf_fromsurf(src, srcobj->surf->w, srcobj->surf->h);
4236+
if (!newsurf)
4237+
return NULL;
4238+
}
4239+
else {
4240+
newsurf = pgSurface_AsSurface(dstobj);
4241+
}
4242+
4243+
if (newsurf->w != src->w || newsurf->h != src->h) {
4244+
return (SDL_Surface *)(RAISE(
4245+
PyExc_ValueError,
4246+
"Destination surface must be the same size as source surface."));
4247+
}
4248+
4249+
if (src->format->BytesPerPixel != newsurf->format->BytesPerPixel) {
4250+
return (SDL_Surface *)(RAISE(
4251+
PyExc_ValueError,
4252+
"Source and destination surfaces need the same format."));
4253+
}
4254+
4255+
int x, y;
4256+
for (y = 0; y < src->h; y += pixel_size) {
4257+
for (x = 0; x < src->w; x += pixel_size) {
4258+
unsigned char r, g, b, a; // current
4259+
Uint64 ra, ga, ba, aa; // averages
4260+
Uint64 size;
4261+
Uint32 color, average;
4262+
Uint8 *pix;
4263+
int width = min(pixel_size, src->w - x);
4264+
int height = min(pixel_size, src->h - y);
4265+
4266+
ra = 0;
4267+
ga = 0;
4268+
ba = 0;
4269+
aa = 0;
4270+
for (int w = 0; w < width; w++) {
4271+
for (int h = 0; h < height; h++) {
4272+
SURF_GET_AT(color, src, x + w, y + h, (Uint8 *)src->pixels,
4273+
src->format, pix);
4274+
SDL_GetRGBA(color, src->format, &r, &g, &b, &a);
4275+
ra += r;
4276+
ga += g;
4277+
ba += b;
4278+
aa += a;
4279+
}
4280+
}
4281+
size = width * height;
4282+
ra /= size;
4283+
ga /= size;
4284+
ba /= size;
4285+
aa /= size;
4286+
4287+
average = SDL_MapRGBA(newsurf->format, ra, ga, ba, aa);
4288+
4289+
printf("%u\n", average);
4290+
for (int w = 0; w < width; w++) {
4291+
for (int h = 0; h < height; h++) {
4292+
SURF_SET_AT(average, newsurf, x + w, y + h,
4293+
(Uint8 *)newsurf->pixels, newsurf->format,
4294+
pix);
4295+
}
4296+
}
4297+
}
4298+
}
4299+
4300+
SDL_UnlockSurface(newsurf);
4301+
4302+
return newsurf;
4303+
}
4304+
4305+
/*
4306+
* anticipated API: pygame.transform.pixelate(surface, pixel_size, dest_surface
4307+
* = None)
4308+
*/
4309+
static PyObject *
4310+
surf_pixelate(PyObject *self, PyObject *args, PyObject *kwargs)
4311+
{
4312+
pgSurfaceObject *src;
4313+
pgSurfaceObject *dst = NULL;
4314+
int pixel_size;
4315+
SDL_Surface *new_surf;
4316+
4317+
static char *kwds[] = {"surface", "pixel_size", "dest_surface", NULL};
4318+
4319+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!i|O!", kwds,
4320+
&pgSurface_Type, &src, &pixel_size,
4321+
&pgSurface_Type, &dst)) {
4322+
return NULL;
4323+
}
4324+
4325+
new_surf = pixelate(src, dst, pixel_size);
4326+
4327+
if (!new_surf) {
4328+
return NULL;
4329+
}
4330+
4331+
if (dst) {
4332+
Py_INCREF(dst);
4333+
return (PyObject *)dst;
4334+
}
4335+
return (PyObject *)pgSurface_New(new_surf);
4336+
}
4337+
42284338
static PyMethodDef _transform_methods[] = {
42294339
{"scale", (PyCFunction)surf_scale, METH_VARARGS | METH_KEYWORDS,
42304340
DOC_TRANSFORM_SCALE},
@@ -4268,6 +4378,8 @@ static PyMethodDef _transform_methods[] = {
42684378
METH_VARARGS | METH_KEYWORDS, DOC_TRANSFORM_SOLIDOVERLAY},
42694379
{"hsl", (PyCFunction)surf_hsl, METH_VARARGS | METH_KEYWORDS,
42704380
DOC_TRANSFORM_HSL},
4381+
{"pixelate", (PyCFunction)surf_pixelate, METH_VARARGS | METH_KEYWORDS,
4382+
DOC_TRANSFORM_PIXELATE},
42714383
{NULL, NULL, 0, NULL}};
42724384

42734385
MODINIT_DEFINE(transform)

0 commit comments

Comments
 (0)