Skip to content

Commit

Permalink
Merge pull request pygame-community#2951 from zoldalma999/frombytes-ABGR
Browse files Browse the repository at this point in the history
Add ABGR format to frombytes and tobytes
  • Loading branch information
ankith26 authored Jun 28, 2024
2 parents 5faa699 + 5b249e3 commit 7d9c288
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 7 deletions.
4 changes: 2 additions & 2 deletions buildconfig/stubs/pygame/image.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ from ._common import FileArg, Literal, IntCoordinate, Coordinate

_BufferStyle = Union[BufferProxy, bytes, bytearray, memoryview]
_to_string_format = Literal[
"P", "RGB", "RGBX", "RGBA", "ARGB", "BGRA", "RGBA_PREMULT", "ARGB_PREMULT"
"P", "RGB", "RGBX", "RGBA", "ARGB", "BGRA", "ABGR", "RGBA_PREMULT", "ARGB_PREMULT"
]
_from_buffer_format = Literal["P", "RGB", "BGR", "BGRA", "RGBX", "RGBA", "ARGB"]
_from_string_format = Literal["P", "RGB", "RGBX", "RGBA", "ARGB", "BGRA"]
_from_string_format = Literal["P", "RGB", "RGBX", "RGBA", "ARGB", "BGRA", "ABGR"]

def load(file: FileArg, namehint: str = "") -> Surface: ...
def load_sized_svg(file: FileArg, size: Coordinate) -> Surface: ...
Expand Down
9 changes: 6 additions & 3 deletions docs/reST/ref/image.rst
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,15 @@ following formats.
* ``RGBA``, 32-bit image with an alpha channel

* ``ARGB``, 32-bit image with alpha channel first

* ``BGRA``, 32-bit image with alpha channel, red and blue channels swapped

* ``BGRA``, 32-bit image with alpha channel, red and blue channels swapped

* ``ABGR``, 32-bit image with alpha channel, reverse order

* ``RGBA_PREMULT``, 32-bit image with colors scaled by alpha channel

* ``ARGB_PREMULT``, 32-bit image with colors scaled by alpha channel, alpha channel first

The 'pitch' argument can be used to specify the pitch/stride per horizontal line
of the image in bytes. It must be equal to or greater than how many bytes
the pixel data of each horizontal line in the image bytes occupies without any
Expand All @@ -248,6 +250,7 @@ following formats.
.. versionadded:: 2.1.3
.. versionchanged:: 2.2.0 Now supports keyword arguments.
.. versionchanged:: 2.5.0 Added a 'pitch' argument.
.. versionchanged:: 2.5.1 Added support for ABGR image format

.. ## pygame.image.tobytes ##
Expand Down
105 changes: 104 additions & 1 deletion src_c/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg)
byte_width = surf->w * 4;
}
else if (!strcmp(format, "RGBX") || !strcmp(format, "ARGB") ||
!strcmp(format, "BGRA")) {
!strcmp(format, "BGRA") || !strcmp(format, "ABGR")) {
byte_width = surf->w * 4;
}
else if (!strcmp(format, "RGBA_PREMULT") ||
Expand Down Expand Up @@ -878,6 +878,83 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg)
}
pgSurface_Unlock(surfobj);
}
else if (!strcmp(format, "ABGR")) {
pgSurface_Lock(surfobj);
switch (PG_SURF_BytesPerPixel(surf)) {
case 1:
for (h = 0; h < surf->h; ++h) {
Uint8 *ptr = (Uint8 *)DATAROW(surf->pixels, h, surf->pitch,
surf->h, flipped);
for (w = 0; w < surf->w; ++w) {
color = *ptr++;
data[3] = (char)surf->format->palette->colors[color].r;
data[2] = (char)surf->format->palette->colors[color].g;
data[1] = (char)surf->format->palette->colors[color].b;
data[0] = (char)255;
data += 4;
}
pad(&data, padding);
}
break;
case 2:
for (h = 0; h < surf->h; ++h) {
Uint16 *ptr = (Uint16 *)DATAROW(
surf->pixels, h, surf->pitch, surf->h, flipped);
for (w = 0; w < surf->w; ++w) {
color = *ptr++;
data[3] = (char)(((color & Rmask) >> Rshift) << Rloss);
data[2] = (char)(((color & Gmask) >> Gshift) << Gloss);
data[1] = (char)(((color & Bmask) >> Bshift) << Bloss);
data[0] = (char)(Amask ? (((color & Amask) >> Ashift)
<< Aloss)
: 255);
data += 4;
}
pad(&data, padding);
}
break;
case 3:
for (h = 0; h < surf->h; ++h) {
Uint8 *ptr = (Uint8 *)DATAROW(surf->pixels, h, surf->pitch,
surf->h, flipped);
for (w = 0; w < surf->w; ++w) {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
color = ptr[0] + (ptr[1] << 8) + (ptr[2] << 16);
#else
color = ptr[2] + (ptr[1] << 8) + (ptr[0] << 16);
#endif
ptr += 3;
data[3] = (char)(((color & Rmask) >> Rshift) << Rloss);
data[2] = (char)(((color & Gmask) >> Gshift) << Gloss);
data[1] = (char)(((color & Bmask) >> Bshift) << Bloss);
data[0] = (char)(Amask ? (((color & Amask) >> Ashift)
<< Aloss)
: 255);
data += 4;
}
pad(&data, padding);
}
break;
case 4:
for (h = 0; h < surf->h; ++h) {
Uint32 *ptr = (Uint32 *)DATAROW(
surf->pixels, h, surf->pitch, surf->h, flipped);
for (w = 0; w < surf->w; ++w) {
color = *ptr++;
data[3] = (char)(((color & Rmask) >> Rshift) << Rloss);
data[2] = (char)(((color & Gmask) >> Gshift) << Gloss);
data[1] = (char)(((color & Bmask) >> Bshift) << Bloss);
data[0] = (char)(Amask ? (((color & Amask) >> Ashift)
<< Aloss)
: 255);
data += 4;
}
pad(&data, padding);
}
break;
}
pgSurface_Unlock(surfobj);
}
else if (!strcmp(format, "RGBA_PREMULT")) {
pgSurface_Lock(surfobj);
switch (PG_SURF_BytesPerPixel(surf)) {
Expand Down Expand Up @@ -1224,6 +1301,32 @@ image_frombytes(PyObject *self, PyObject *arg, PyObject *kwds)
}
SDL_UnlockSurface(surf);
}
else if (!strcmp(format, "ABGR")) {
if (pitch == -1) {
pitch = w * 4;
}
else if (pitch < w * 4) {
return RAISE(PyExc_ValueError,
"Pitch must be greater than or equal to the width * "
"4 as per the format");
}

if (len != (Py_ssize_t)pitch * h)
return RAISE(
PyExc_ValueError,
"Bytes length does not equal format and resolution size");
surf = PG_CreateSurface(w, h, SDL_PIXELFORMAT_ABGR32);
if (!surf)
return RAISE(pgExc_SDLError, SDL_GetError());
SDL_LockSurface(surf);
for (looph = 0; looph < h; ++looph) {
Uint32 *pix = (Uint32 *)DATAROW(surf->pixels, looph, surf->pitch,
h, flipped);
memcpy(pix, data, w * sizeof(Uint32));
data += pitch;
}
SDL_UnlockSurface(surf);
}
else
return RAISE(PyExc_ValueError, "Unrecognized type of format");

Expand Down
2 changes: 1 addition & 1 deletion test/image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ def test_frombytes__and_tobytes(self):

import itertools

fmts = ("RGBA", "ARGB", "BGRA")
fmts = ("RGBA", "ARGB", "BGRA", "ABGR")
fmt_permutations = itertools.permutations(fmts, 2)
fmt_combinations = itertools.combinations(fmts, 2)

Expand Down

0 comments on commit 7d9c288

Please sign in to comment.