diff --git a/Tests/images/imagedraw/triangle_right_width.png b/Tests/images/imagedraw/triangle_right_width.png new file mode 100644 index 00000000000..57b73553a6d Binary files /dev/null and b/Tests/images/imagedraw/triangle_right_width.png differ diff --git a/Tests/images/imagedraw/triangle_right_width_no_fill.png b/Tests/images/imagedraw/triangle_right_width_no_fill.png new file mode 100644 index 00000000000..dd65be6be7b Binary files /dev/null and b/Tests/images/imagedraw/triangle_right_width_no_fill.png differ diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 1b2909bed7c..1423d9cbcac 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -945,6 +945,18 @@ def test_triangle_right(): ) +@pytest.mark.parametrize( + "fill, suffix", + ((BLACK, "width"), (None, "width_no_fill")), +) +def test_triangle_right_width(fill, suffix): + img, draw = create_base_image_draw((100, 100)) + draw.polygon([(15, 25), (85, 25), (50, 60)], fill, WHITE, width=5) + assert_image_equal_tofile( + img, os.path.join(IMAGES_PATH, "triangle_right_" + suffix + ".png") + ) + + def test_line_horizontal(): img, draw = create_base_image_draw((20, 20)) draw.line((5, 5, 14, 5), BLACK, 2) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index eeae1782a72..610ccd4c7ee 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -233,13 +233,35 @@ def point(self, xy, fill=None): if ink is not None: self.draw.draw_points(xy, ink) - def polygon(self, xy, fill=None, outline=None): + def polygon(self, xy, fill=None, outline=None, width=1): """Draw a polygon.""" ink, fill = self._getink(outline, fill) if fill is not None: self.draw.draw_polygon(xy, fill, 1) - if ink is not None and ink != fill: - self.draw.draw_polygon(xy, ink, 0) + if ink is not None and ink != fill and width != 0: + if width == 1: + self.draw.draw_polygon(xy, ink, 0, width) + else: + # To avoid expanding the polygon outwards, + # use the fill as a mask + mask = Image.new("1", self.im.size) + mask_ink = self._getink(1)[0] + + fill_im = mask.copy() + draw = Draw(fill_im) + draw.draw.draw_polygon(xy, mask_ink, 1) + + ink_im = mask.copy() + draw = Draw(ink_im) + width = width * 2 - 1 + draw.draw.draw_polygon(xy, mask_ink, 0, width) + + mask.paste(ink_im, mask=fill_im) + + im = Image.new(self.mode, self.im.size) + draw = Draw(im) + draw.draw.draw_polygon(xy, ink, 0, width) + self.im.paste(im.im, (0, 0) + im.size, mask.im) def regular_polygon( self, bounding_circle, n_sides, rotation=0, fill=None, outline=None diff --git a/src/_imaging.c b/src/_imaging.c index e2193fec3c5..aba907f88ba 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -3124,7 +3124,8 @@ _draw_polygon(ImagingDrawObject *self, PyObject *args) { PyObject *data; int ink; int fill = 0; - if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &fill)) { + int width = 0; + if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width)) { return NULL; } @@ -3153,7 +3154,7 @@ _draw_polygon(ImagingDrawObject *self, PyObject *args) { free(xy); - if (ImagingDrawPolygon(self->image->image, n, ixy, &ink, fill, self->blend) < 0) { + if (ImagingDrawPolygon(self->image->image, n, ixy, &ink, fill, width, self->blend) < 0) { free(ixy); return NULL; } diff --git a/src/libImaging/Draw.c b/src/libImaging/Draw.c index 1cd9a95ad0b..69b804deeb2 100644 --- a/src/libImaging/Draw.c +++ b/src/libImaging/Draw.c @@ -742,7 +742,7 @@ ImagingDrawRectangle( } int -ImagingDrawPolygon(Imaging im, int count, int *xy, const void *ink_, int fill, int op) { +ImagingDrawPolygon(Imaging im, int count, int *xy, const void *ink_, int fill, int width, int op) { int i, n, x0, y0, x1, y1; DRAW *draw; INT32 ink; @@ -790,10 +790,17 @@ ImagingDrawPolygon(Imaging im, int count, int *xy, const void *ink_, int fill, i } else { /* Outline */ - for (i = 0; i < count - 1; i++) { - draw->line(im, xy[i * 2], xy[i * 2 + 1], xy[i * 2 + 2], xy[i * 2 + 3], ink); + if (width == 1) { + for (i = 0; i < count - 1; i++) { + draw->line(im, xy[i * 2], xy[i * 2 + 1], xy[i * 2 + 2], xy[i * 2 + 3], ink); + } + draw->line(im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink); + } else { + for (i = 0; i < count - 1; i++) { + ImagingDrawWideLine(im, xy[i * 2], xy[i * 2 + 1], xy[i * 2 + 2], xy[i * 2 + 3], ink_, width, op); + } + ImagingDrawWideLine(im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink_, width, op); } - draw->line(im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink); } return 0; diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index 6d18dee4ef5..9b1c1024dc4 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -487,7 +487,7 @@ ImagingDrawPieslice( extern int ImagingDrawPoint(Imaging im, int x, int y, const void *ink, int op); extern int -ImagingDrawPolygon(Imaging im, int points, int *xy, const void *ink, int fill, int op); +ImagingDrawPolygon(Imaging im, int points, int *xy, const void *ink, int fill, int width, int op); extern int ImagingDrawRectangle( Imaging im,