diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 4c0dbb4cc..17cb615a5 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -328,6 +328,36 @@ class TestCffi(AccessTest): assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0) +class TestImagePutPixelError(AccessTest): + def test_putpixel_error_message(self): + for mode, reason, accept_tuple in [ + ("L", "color must be int or tuple", True), + ("LA", "color must be int or tuple", True), + ("RGB", "color must be int or tuple", True), + ("RGBA", "color must be int or tuple", True), + ("I", "color must be int", False), + ("I;16", "color must be int", False), + ("BGR;15", "color must be int", False), + ]: + im = hopper(mode) + + for v in ["foo", 1.0, None]: + with pytest.raises(TypeError, match=reason): + im.putpixel((0, 0), v) + + if not accept_tuple: + with pytest.raises(TypeError, match=reason): + im.putpixel((0, 0), (10,)) + + with pytest.raises(OverflowError): + im.putpixel((0, 0), 2 ** 80) + + for mode in ["BGR;15"]: + im = hopper(mode) + 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;