diff --git a/Tests/images/imagedraw_ellipse_various_sizes.png b/Tests/images/imagedraw_ellipse_various_sizes.png index 11a1be6faeb..5e3cf22b4ad 100644 Binary files a/Tests/images/imagedraw_ellipse_various_sizes.png and b/Tests/images/imagedraw_ellipse_various_sizes.png differ diff --git a/Tests/images/imagedraw_ellipse_various_sizes_filled.png b/Tests/images/imagedraw_ellipse_various_sizes_filled.png index d71e175b8fd..dd2f641f1ea 100644 Binary files a/Tests/images/imagedraw_ellipse_various_sizes_filled.png and b/Tests/images/imagedraw_ellipse_various_sizes_filled.png differ diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index ea0711ad53c..2cc1a19de6c 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -355,7 +355,13 @@ def ellipse_various_sizes_helper(filled): for w in ellipse_sizes: y = 1 for h in ellipse_sizes: - border = [x, y, x + w - 1, y + h - 1] + x1 = x + w + if w: + x1 -= 1 + y1 = y + h + if h: + y1 -= 1 + border = [x, y, x1, y1] if filled: draw.ellipse(border, fill="white") else: @@ -932,9 +938,6 @@ def test_square(): img, draw = create_base_image_draw((10, 10)) draw.rectangle((2, 2, 7, 7), BLACK) assert_image_equal_tofile(img, expected, "square as normal rectangle failed") - img, draw = create_base_image_draw((10, 10)) - draw.rectangle((7, 7, 2, 2), BLACK) - assert_image_equal_tofile(img, expected, "square as inverted rectangle failed") def test_triangle_right(): @@ -1499,3 +1502,20 @@ def test_polygon2(): draw.polygon([(18, 30), (19, 31), (18, 30), (85, 30), (60, 72)], "red") expected = "Tests/images/imagedraw_outline_polygon_RGB.png" assert_image_similar_tofile(im, expected, 1) + + +def test_incorrectly_ordered_coordinates(): + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + with pytest.raises(TypeError): + draw.arc((1, 1, 0, 0), 10, 260) + with pytest.raises(TypeError): + draw.chord((1, 1, 0, 0), 10, 260) + with pytest.raises(TypeError): + draw.ellipse((1, 1, 0, 0)) + with pytest.raises(TypeError): + draw.pieslice((1, 1, 0, 0), 10, 260) + with pytest.raises(TypeError): + draw.rectangle((1, 1, 0, 0)) + with pytest.raises(TypeError): + draw.rounded_rectangle((1, 1, 0, 0)) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index a55ebbe8eeb..94b10b8fd16 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -303,6 +303,12 @@ def rounded_rectangle( (x0, y0), (x1, y1) = xy else: x0, y0, x1, y1 = xy + if x1 < x0 or y1 < y0: + msg = ( + "x1 must be greater than or equal to x0," + " and y1 must be greater than or equal to y0" + ) + raise TypeError(msg) if corners is None: corners = (True, True, True, True) diff --git a/src/_imaging.c b/src/_imaging.c index cece2e93a33..bb92a67008a 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -251,6 +251,8 @@ PyImaging_GetBuffer(PyObject *buffer, Py_buffer *view) { static const char *must_be_sequence = "argument must be a sequence"; static const char *must_be_two_coordinates = "coordinate list must contain exactly 2 coordinates"; +static const char *incorrectly_ordered_coordinates = + "x1 must be greater than or equal to x0, and y1 must be greater than or equal to y0"; static const char *wrong_mode = "unrecognized image mode"; static const char *wrong_raw_mode = "unrecognized raw mode"; static const char *outside_image = "image index out of range"; @@ -2805,6 +2807,11 @@ _draw_arc(ImagingDrawObject *self, PyObject *args) { free(xy); return NULL; } + if (xy[2] < xy[0] || xy[3] < xy[1]) { + PyErr_SetString(PyExc_TypeError, incorrectly_ordered_coordinates); + free(xy); + return NULL; + } n = ImagingDrawArc( self->image->image, @@ -2886,6 +2893,11 @@ _draw_chord(ImagingDrawObject *self, PyObject *args) { free(xy); return NULL; } + if (xy[2] < xy[0] || xy[3] < xy[1]) { + PyErr_SetString(PyExc_TypeError, incorrectly_ordered_coordinates); + free(xy); + return NULL; + } n = ImagingDrawChord( self->image->image, @@ -2932,6 +2944,11 @@ _draw_ellipse(ImagingDrawObject *self, PyObject *args) { free(xy); return NULL; } + if (xy[2] < xy[0] || xy[3] < xy[1]) { + PyErr_SetString(PyExc_TypeError, incorrectly_ordered_coordinates); + free(xy); + return NULL; + } n = ImagingDrawEllipse( self->image->image, @@ -3101,6 +3118,11 @@ _draw_pieslice(ImagingDrawObject *self, PyObject *args) { free(xy); return NULL; } + if (xy[2] < xy[0] || xy[3] < xy[1]) { + PyErr_SetString(PyExc_TypeError, incorrectly_ordered_coordinates); + free(xy); + return NULL; + } n = ImagingDrawPieslice( self->image->image, @@ -3197,6 +3219,11 @@ _draw_rectangle(ImagingDrawObject *self, PyObject *args) { free(xy); return NULL; } + if (xy[2] < xy[0] || xy[3] < xy[1]) { + PyErr_SetString(PyExc_TypeError, incorrectly_ordered_coordinates); + free(xy); + return NULL; + } n = ImagingDrawRectangle( self->image->image,