diff --git a/Tests/images/imagedraw_rectangle_width.png b/Tests/images/imagedraw_rectangle_width.png new file mode 100644 index 000000000..e39659921 Binary files /dev/null and b/Tests/images/imagedraw_rectangle_width.png differ diff --git a/Tests/images/imagedraw_rectangle_width_fill.png b/Tests/images/imagedraw_rectangle_width_fill.png new file mode 100644 index 000000000..d5243c608 Binary files /dev/null and b/Tests/images/imagedraw_rectangle_width_fill.png differ diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 1c8fe3153..cd4eb2780 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -343,6 +343,30 @@ class TestImageDraw(PillowTestCase): # Assert self.assert_image_similar(im, Image.open(expected), 1) + def test_rectangle_width(self): + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + expected = "Tests/images/imagedraw_rectangle_width.png" + + # Act + draw.rectangle(BBOX1, outline="green", width=5) + + # Assert + self.assert_image_equal(im, Image.open(expected)) + + def test_rectangle_width_fill(self): + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + expected = "Tests/images/imagedraw_rectangle_width_fill.png" + + # Act + draw.rectangle(BBOX1, fill="blue", outline="green", width=5) + + # Assert + self.assert_image_equal(im, Image.open(expected)) + def test_floodfill(self): # Arrange im = Image.new("RGB", (W, H)) diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 6057712e2..7b28aafb0 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -220,7 +220,7 @@ Methods :param outline: Color to use for the outline. :param fill: Color to use for the fill. -.. py:method:: PIL.ImageDraw.ImageDraw.rectangle(xy, fill=None, outline=None) +.. py:method:: PIL.ImageDraw.ImageDraw.rectangle(xy, fill=None, outline=None, width=0) Draws a rectangle. @@ -229,6 +229,9 @@ Methods is just outside the drawn rectangle. :param outline: Color to use for the outline. :param fill: Color to use for the fill. + :param width: The line width, in pixels. + + .. versionadded:: 5.2.0 .. py:method:: PIL.ImageDraw.ImageDraw.shape(shape, fill=None, outline=None) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 5bc890252..1bbb6e6a6 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -186,13 +186,13 @@ class ImageDraw(object): if ink is not None: self.draw.draw_polygon(xy, ink, 0) - def rectangle(self, xy, fill=None, outline=None): + def rectangle(self, xy, fill=None, outline=None, width=0): """Draw a rectangle.""" ink, fill = self._getink(outline, fill) if fill is not None: self.draw.draw_rectangle(xy, fill, 1) if ink is not None: - self.draw.draw_rectangle(xy, ink, 0) + self.draw.draw_rectangle(xy, ink, 0, width) def _multiline_check(self, text): """Draw text.""" diff --git a/src/_imaging.c b/src/_imaging.c index 5004becee..3cced9a0f 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -2730,7 +2730,7 @@ _draw_lines(ImagingDrawObject* self, PyObject* args) if (width <= 1) { double *p = NULL; - for (i = 0; i < n-1; i++) { + for (i = 0; i < n-1; i++) { p = &xy[i+i]; if (ImagingDrawLine( self->image->image, @@ -2931,7 +2931,8 @@ _draw_rectangle(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; n = PyPath_Flatten(data, &xy); @@ -2945,7 +2946,7 @@ _draw_rectangle(ImagingDrawObject* self, PyObject* args) n = ImagingDrawRectangle(self->image->image, (int) xy[0], (int) xy[1], (int) xy[2], (int) xy[3], - &ink, fill, self->blend + &ink, fill, width, self->blend ); free(xy); diff --git a/src/libImaging/Draw.c b/src/libImaging/Draw.c index 7b7c5fac0..fee1cac63 100644 --- a/src/libImaging/Draw.c +++ b/src/libImaging/Draw.c @@ -634,8 +634,9 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, int ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, - const void* ink_, int fill, int op) + const void* ink_, int fill, int width, int op) { + int i; int y; int tmp; DRAW* draw; @@ -662,13 +663,16 @@ ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, draw->hline(im, x0, y, x1, ink); } else { - /* outline */ - draw->line(im, x0, y0, x1, y0, ink); - draw->line(im, x1, y0, x1, y1, ink); - draw->line(im, x1, y1, x0, y1, ink); - draw->line(im, x0, y1, x0, y0, ink); - + if (width == 0) { + width = 1; + } + for (i = 0; i < width; i++) { + draw->hline(im, x0, y0+i, x1, ink); + draw->hline(im, x0, y1-i, x1, ink); + draw->line(im, x1-i, y0, x1-i, y1, ink); + draw->line(im, x0+i, y1, x0+i, y0, ink); + } } return 0; diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index 6b553c928..4588602b1 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -368,7 +368,7 @@ 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); extern int ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, - const void* ink, int fill, int op); + const void* ink, int fill, int width, int op); /* Level 2 graphics (WORK IN PROGRESS) */ extern ImagingOutline ImagingOutlineNew(void);