diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index 547a6c2c678..249b52ca8a0 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -225,6 +225,10 @@ def test_trns_RGB(tmp_path: Path) -> None: assert "transparency" not in im_p.info im_p.save(f) + im.info["transparency"] = list(im.info["transparency"]) + im_rgba = im.convert("RGBA") + assert "transparency" not in im_rgba.info + im = Image.new("RGB", (1, 1)) im.info["transparency"] = im.getpixel((0, 0)) im_p = im.convert("P", palette=Image.Palette.ADAPTIVE) @@ -353,19 +357,24 @@ def test_matrix_xyz(mode: str) -> None: def test_matrix_identity() -> None: # Arrange - im = hopper("RGB") + im = hopper() + assert im.mode == "RGB" + # fmt: off identity_matrix = ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0) # fmt: on - assert im.mode == "RGB" # Act # Convert with an identity matrix - converted_im = im.convert(mode="RGB", matrix=identity_matrix) + converted_im = im.convert("RGB", identity_matrix) # Assert # No change assert_image_equal(converted_im, im) + + # Test list + converted_im = im.convert("RGB", list(identity_matrix)) + assert_image_equal(converted_im, im) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index ebbd8fd35f8..90fe6aa63ab 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1017,7 +1017,7 @@ def verify(self) -> None: def convert( self, mode: str | None = None, - matrix: tuple[float, ...] | None = None, + matrix: list[float] | tuple[float, ...] | None = None, dither: Dither | None = None, palette: Palette = Palette.WEB, colors: int = 256, @@ -1052,7 +1052,7 @@ def convert( :param mode: The requested mode. See: :ref:`concept-modes`. :param matrix: An optional conversion matrix. If given, this - should be 4- or 12-tuple containing floating point values. + should be 4- or 12-sequence containing floating point values. :param dither: Dithering method, used when converting from mode "RGB" to "P" or from "RGB" or "L" to "1". Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG` @@ -1091,7 +1091,7 @@ def convert( transparency = new_im.info["transparency"] def convert_transparency( - m: tuple[float, ...], v: tuple[int, int, int] + m: list[float] | tuple[float, ...], v: tuple[int, int, int] ) -> int: value = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * 0.5 return max(0, min(255, int(value))) diff --git a/src/_imaging.c b/src/_imaging.c index 09793f36bea..c7917a23715 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -1049,8 +1049,15 @@ static PyObject * _convert_matrix(ImagingObject *self, PyObject *args) { char *mode_name; float m[12]; - if (!PyArg_ParseTuple(args, "s(ffff)", &mode_name, m + 0, m + 1, m + 2, m + 3)) { - PyErr_Clear(); + PyObject *matrix; + if (!PyArg_ParseTuple(args, "sO", &mode_name, &matrix)) { + return NULL; + } + Py_ssize_t size = PySequence_Size(matrix); + if (size == -1) { + return NULL; + } + if (size == 12) { if (!PyArg_ParseTuple( args, "s(ffffffffffff)", @@ -1070,27 +1077,35 @@ _convert_matrix(ImagingObject *self, PyObject *args) { )) { return NULL; } + } else if (!PyArg_ParseTuple( + args, "s(ffff)", &mode_name, m + 0, m + 1, m + 2, m + 3 + )) { + return NULL; } const ModeID mode = findModeID(mode_name); - return PyImagingNew(ImagingConvertMatrix(self->image, mode, m)); } static PyObject * _convert_transparent(ImagingObject *self, PyObject *args) { char *mode_name; - int r, g, b; - if (PyArg_ParseTuple(args, "s(iii)", &mode_name, &r, &g, &b)) { - const ModeID mode = findModeID(mode_name); - return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, g, b)); + int r, g = 0, b = 0; + PyObject *transparency; + if (!PyArg_ParseTuple(args, "sO", &mode_name, &transparency)) { + return NULL; } - PyErr_Clear(); - if (PyArg_ParseTuple(args, "si", &mode_name, &r)) { - const ModeID mode = findModeID(mode_name); - return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, 0, 0)); + + if (PySequence_Check(transparency)) { + if (!PyArg_ParseTuple(args, "s(iii)", &mode_name, &r, &g, &b)) { + return NULL; + } + } else if (!PyArg_ParseTuple(args, "si", &mode_name, &r)) { + return NULL; } - return NULL; + + const ModeID mode = findModeID(mode_name); + return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, g, b)); } static PyObject *