From d8c3135b6bcff0105453346dfa35886615bf0505 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 28 Aug 2023 20:12:23 +1000 Subject: [PATCH 1/3] Allow getpixel to accept a list --- Tests/test_image_access.py | 4 ++++ src/_imaging.c | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index c9db3aee730..f80bc9c10a9 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -213,6 +213,10 @@ def check(self, mode, expected_color=None): def test_basic(self, mode): self.check(mode) + def test_list(self): + im = hopper() + assert im.getpixel([0, 0]) == (20, 20, 70) + @pytest.mark.parametrize("mode", ("I;16", "I;16B")) @pytest.mark.parametrize( "expected_color", (2**15 - 1, 2**15, 2**15 + 1, 2**16 - 1) diff --git a/src/_imaging.c b/src/_imaging.c index 95da2772d56..736f347a3ca 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -1146,11 +1146,15 @@ static inline int _getxy(PyObject *xy, int *x, int *y) { PyObject *value; - if (!PyTuple_Check(xy) || PyTuple_GET_SIZE(xy) != 2) { + int tuple = PyTuple_Check(xy); + if ( + !(tuple && PyTuple_GET_SIZE(xy) == 2) && + !(PyList_Check(xy) && PyList_GET_SIZE(xy) == 2) + ) { goto badarg; } - value = PyTuple_GET_ITEM(xy, 0); + value = tuple ? PyTuple_GET_ITEM(xy, 0) : PyList_GET_ITEM(xy, 0); if (PyLong_Check(value)) { *x = PyLong_AS_LONG(value); } else if (PyFloat_Check(value)) { @@ -1164,7 +1168,7 @@ _getxy(PyObject *xy, int *x, int *y) { } } - value = PyTuple_GET_ITEM(xy, 1); + value = tuple ? PyTuple_GET_ITEM(xy, 1) : PyList_GET_ITEM(xy, 1); if (PyLong_Check(value)) { *y = PyLong_AS_LONG(value); } else if (PyFloat_Check(value)) { From 69a81dd8673f7c29f24d16061d2d7a871405333c Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 28 Aug 2023 22:43:20 +1000 Subject: [PATCH 2/3] Convert list to tuple in Python instead of C --- src/PIL/Image.py | 2 ++ src/_imaging.c | 10 +++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 476ed012278..2b7ec6bec14 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1565,6 +1565,8 @@ def getpixel(self, xy): self.load() if self.pyaccess: return self.pyaccess.getpixel(xy) + if isinstance(xy, list): + xy = tuple(xy) return self.im.getpixel(xy) def getprojection(self): diff --git a/src/_imaging.c b/src/_imaging.c index 736f347a3ca..95da2772d56 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -1146,15 +1146,11 @@ static inline int _getxy(PyObject *xy, int *x, int *y) { PyObject *value; - int tuple = PyTuple_Check(xy); - if ( - !(tuple && PyTuple_GET_SIZE(xy) == 2) && - !(PyList_Check(xy) && PyList_GET_SIZE(xy) == 2) - ) { + if (!PyTuple_Check(xy) || PyTuple_GET_SIZE(xy) != 2) { goto badarg; } - value = tuple ? PyTuple_GET_ITEM(xy, 0) : PyList_GET_ITEM(xy, 0); + value = PyTuple_GET_ITEM(xy, 0); if (PyLong_Check(value)) { *x = PyLong_AS_LONG(value); } else if (PyFloat_Check(value)) { @@ -1168,7 +1164,7 @@ _getxy(PyObject *xy, int *x, int *y) { } } - value = tuple ? PyTuple_GET_ITEM(xy, 1) : PyList_GET_ITEM(xy, 1); + value = PyTuple_GET_ITEM(xy, 1); if (PyLong_Check(value)) { *y = PyLong_AS_LONG(value); } else if (PyFloat_Check(value)) { From f9f367fe54c68e856a5630462f6cbad4ce49c186 Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Wed, 30 Aug 2023 07:27:09 +1000 Subject: [PATCH 3/3] Always cast to a tuple Co-authored-by: Alexander Karpinsky --- src/PIL/Image.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 2b7ec6bec14..6ea711b565a 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1565,9 +1565,7 @@ def getpixel(self, xy): self.load() if self.pyaccess: return self.pyaccess.getpixel(xy) - if isinstance(xy, list): - xy = tuple(xy) - return self.im.getpixel(xy) + return self.im.getpixel(tuple(xy)) def getprojection(self): """