Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions Tests/test_image_putalpha.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

import pytest

from PIL import Image


Expand Down Expand Up @@ -39,6 +41,9 @@ def test_promote() -> None:
assert im.mode == "RGBA"
assert im.getpixel((0, 0)) == (1, 2, 3, 4)

with pytest.raises(ValueError, match="image has wrong mode"):
im.im.setalpha()


def test_readonly() -> None:
im = Image.new("RGB", (1, 1), (1, 2, 3))
Expand Down
34 changes: 0 additions & 34 deletions Tests/test_lib_image.py

This file was deleted.

22 changes: 11 additions & 11 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2045,19 +2045,19 @@ def putalpha(self, alpha: Image | int) -> None:

self._ensure_mutable()

if self.mode not in ("LA", "PA", "RGBA"):
# attempt to promote self to a matching alpha mode
if self.mode in ("RGB", "RGBX"):
# promote self to RGBA
self.im.setalpha()
self._mode = "RGBA"
elif self.mode not in ("LA", "PA", "RGBA"):
try:
# do things the hard way
mode = getmodebase(self.mode) + "A"
try:
self.im.setmode(mode)
except (AttributeError, ValueError) as e:
# do things the hard way
im = self.im.convert(mode)
if im.mode not in ("LA", "PA", "RGBA"):
msg = "alpha channel could not be added"
raise ValueError(msg) from e # sanity check
self.im = im
im = self.im.convert(mode)
if im.mode not in ("LA", "PA", "RGBA"):
msg = "alpha channel could not be added"
raise ValueError(msg) # sanity check
self.im = im
self._mode = self.im.mode
except KeyError as e:
msg = "illegal image mode"
Expand Down
45 changes: 8 additions & 37 deletions src/_imaging.c
Original file line number Diff line number Diff line change
Expand Up @@ -2053,45 +2053,16 @@ _reduce(ImagingObject *self, PyObject *args) {
return PyImagingNew(imOut);
}

static int
isRGB(const ModeID mode) {
return mode == IMAGING_MODE_RGB || mode == IMAGING_MODE_RGBA ||
mode == IMAGING_MODE_RGBX;
}

static PyObject *
im_setmode(ImagingObject *self, PyObject *args) {
im_setalpha(ImagingObject *self, PyObject *args) {
/* attempt to modify the mode of an image in place */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is a little stale now?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it? The method is still modifying the mode of an image in place. It's more specific now, is all.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose...

Should this function know how to do P-to-PA and L-to-LA too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thought occurred to me. It is a bit different to RGB, since RGB already has the same pixelsize as RGBA.

Do you mind if that is a follow-up PR? I would rather tidy things up first.


Imaging im;

char *mode_name;
Py_ssize_t modelen;
if (!PyArg_ParseTuple(args, "s#:setmode", &mode_name, &modelen)) {
return NULL;
}

const ModeID mode = findModeID(mode_name);

im = self->image;

/* move all logic in here to the libImaging primitive */

if (im->mode == mode) {
; /* same mode; always succeeds */
} else if (isRGB(im->mode) && isRGB(mode)) {
/* color to color */
im->mode = mode;
im->bands = modelen;
if (mode == IMAGING_MODE_RGBA) {
(void)ImagingFillBand(im, 3, 255);
}
} else {
/* trying doing an in-place conversion */
if (!ImagingConvertInPlace(im, mode)) {
return NULL;
}
Imaging im = self->image;
if (im->mode != IMAGING_MODE_RGB && im->mode != IMAGING_MODE_RGBX) {
return ImagingError_ModeError();
}
im->mode = IMAGING_MODE_RGBA;
im->bands = 4;
(void)ImagingFillBand(im, 3, 255);

if (self->access) {
ImagingAccessDelete(im, self->access);
Expand Down Expand Up @@ -3740,7 +3711,7 @@ static struct PyMethodDef methods[] = {
{"split", (PyCFunction)_split, METH_NOARGS},
{"fillband", (PyCFunction)_fillband, METH_VARARGS},

{"setmode", (PyCFunction)im_setmode, METH_VARARGS},
{"setalpha", (PyCFunction)im_setalpha, METH_NOARGS},
Comment thread
radarhere marked this conversation as resolved.

{"getpalette", (PyCFunction)_getpalette, METH_VARARGS},
{"getpalettemode", (PyCFunction)_getpalettemode, METH_NOARGS},
Expand Down
24 changes: 0 additions & 24 deletions src/libImaging/Convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -1732,27 +1732,3 @@ ImagingConvertTransparent(Imaging imIn, const ModeID mode, int r, int g, int b)

return imOut;
}

Imaging
ImagingConvertInPlace(Imaging imIn, const ModeID mode) {
ImagingSectionCookie cookie;
ImagingShuffler convert;
int y;

/* limited support for inplace conversion */
if (imIn->mode == IMAGING_MODE_L && mode == IMAGING_MODE_1) {
convert = l2bit;
} else if (imIn->mode == IMAGING_MODE_1 && mode == IMAGING_MODE_L) {
convert = bit2l;
} else {
return ImagingError_ModeError();
}

ImagingSectionEnter(&cookie);
for (y = 0; y < imIn->ysize; y++) {
(*convert)((UINT8 *)imIn->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
}
ImagingSectionLeave(&cookie);

return imIn;
}
2 changes: 0 additions & 2 deletions src/libImaging/Imaging.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,6 @@ ImagingConvert(
Imaging imOut, Imaging imIn, ModeID mode, ImagingPalette palette, int dither
);
extern Imaging
ImagingConvertInPlace(Imaging im, ModeID mode);
extern Imaging
ImagingConvertMatrix(Imaging im, ModeID mode, const float m[12]);
extern Imaging
ImagingConvertTransparent(Imaging im, ModeID mode, int r, int g, int b);
Expand Down
Loading