diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 3f0c6ab3b..9afeb77f7 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -327,6 +327,38 @@ class TestCffi(AccessTest): assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0) +class TestImagePutPixelError(AccessTest): + IMAGE_MODES1 = ["L", "LA", "RGB", "RGBA"] + IMAGE_MODES2 = ["I", "I;16", "BGR;15"] + INVALID_TYPES1 = ["foo", 1.0, None] + INVALID_TYPES2 = [*INVALID_TYPES1, (10,)] + + @pytest.mark.parametrize("mode", IMAGE_MODES1) + def test_putpixel_type_error1(self, mode): + im = hopper(mode) + for v in self.INVALID_TYPES1: + with pytest.raises(TypeError, match="color must be int or tuple"): + im.putpixel((0, 0), v) + + @pytest.mark.parametrize("mode", IMAGE_MODES2) + def test_putpixel_type_error2(self, mode): + im = hopper(mode) + for v in self.INVALID_TYPES2: + with pytest.raises(TypeError, match="color must be int"): + im.putpixel((0, 0), v) + + @pytest.mark.parametrize("mode", IMAGE_MODES1 + IMAGE_MODES2) + def test_putpixel_overflow_error(self, mode): + im = hopper(mode) + with pytest.raises(OverflowError): + im.putpixel((0, 0), 2 ** 80) + + def test_putpixel_unrecognized_mode(self): + im = hopper("BGR;15") + with pytest.raises(ValueError, match="unrecognized image mode"): + im.putpixel((0, 0), 0) + + class TestEmbeddable: @pytest.mark.skipif( not is_win32() or on_ci(), diff --git a/src/_imaging.c b/src/_imaging.c index 1ed5e8a42..d3159a494 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -521,12 +521,20 @@ getink(PyObject* color, Imaging im, char* ink) if (im->type == IMAGING_TYPE_UINT8 || im->type == IMAGING_TYPE_INT32 || im->type == IMAGING_TYPE_SPECIAL) { - if (PyLong_Check(color)) { - r = PyLong_AsLongLong(color); + if (PyLong_Check(color)) { + r = PyLong_AsLongLong(color); + if (r == -1 && PyErr_Occurred()) { + return NULL; + } rIsInt = 1; - } - if (r == -1 && PyErr_Occurred()) { - rIsInt = 0; + } else if (im->type == IMAGING_TYPE_UINT8) { + if (!PyTuple_Check(color)) { + PyErr_SetString(PyExc_TypeError, "color must be int or tuple"); + return NULL; + } + } else { + PyErr_SetString(PyExc_TypeError, "color must be int"); + return NULL; } } @@ -570,9 +578,6 @@ getink(PyObject* color, Imaging im, char* ink) return ink; case IMAGING_TYPE_INT32: /* signed integer */ - if (rIsInt != 1) { - return NULL; - } itmp = r; memcpy(ink, &itmp, sizeof(itmp)); return ink; @@ -587,9 +592,6 @@ getink(PyObject* color, Imaging im, char* ink) return ink; case IMAGING_TYPE_SPECIAL: if (strncmp(im->mode, "I;16", 4) == 0) { - if (rIsInt != 1) { - return NULL; - } ink[0] = (UINT8) r; ink[1] = (UINT8) (r >> 8); ink[2] = ink[3] = 0;