diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 0a699e2ab..69d09e03d 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -2,6 +2,7 @@ from __future__ import annotations import contextlib import os.path +from typing import Sequence import pytest @@ -265,6 +266,21 @@ def test_chord_too_fat() -> None: assert_image_equal_tofile(im, "Tests/images/imagedraw_chord_too_fat.png") +@pytest.mark.parametrize("mode", ("RGB", "L")) +@pytest.mark.parametrize("xy", ((W / 2, H / 2), [W / 2, H / 2])) +def test_circle(mode: str, xy: Sequence[float]) -> None: + # Arrange + im = Image.new(mode, (W, H)) + draw = ImageDraw.Draw(im) + expected = f"Tests/images/imagedraw_ellipse_{mode}.png" + + # Act + draw.circle(xy, 25, fill="green", outline="blue") + + # Assert + assert_image_similar_tofile(im, expected, 1) + + @pytest.mark.parametrize("mode", ("RGB", "L")) @pytest.mark.parametrize("bbox", BBOX) def test_ellipse(mode: str, bbox: Coords) -> None: diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 4ccfacae7..1404869ca 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -227,6 +227,18 @@ Methods .. versionadded:: 5.3.0 +.. py:method:: ImageDraw.circle(xy, radius, fill=None, outline=None, width=1) + + Draws a circle with a given radius centering on a point. + + .. versionadded:: 10.4.0 + + :param xy: The point for the center of the circle, e.g. ``(x, y)``. + :param radius: Radius of the circle. + :param outline: Color to use for the outline. + :param fill: Color to use for the fill. + :param width: The line width, in pixels. + .. py:method:: ImageDraw.ellipse(xy, fill=None, outline=None, width=1) Draws an ellipse inside the given bounding box. diff --git a/docs/releasenotes/10.4.0.rst b/docs/releasenotes/10.4.0.rst index 41f33102f..e0d695a8b 100644 --- a/docs/releasenotes/10.4.0.rst +++ b/docs/releasenotes/10.4.0.rst @@ -45,6 +45,13 @@ TODO API Additions ============= +ImageDraw.circle +^^^^^^^^^^^^^^^^ + +Added :py:meth:`~PIL.ImageDraw.ImageDraw.circle`. It provides the same functionality as +:py:meth:`~PIL.ImageDraw.ImageDraw.ellipse`, but instead of taking a bounding box, it +takes a center point and radius. + TODO ^^^^ diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 42f2ee8c7..17c176430 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -181,6 +181,13 @@ class ImageDraw: if ink is not None and ink != fill and width != 0: self.draw.draw_ellipse(xy, ink, 0, width) + def circle( + self, xy: Sequence[float], radius: float, fill=None, outline=None, width=1 + ) -> None: + """Draw a circle given center coordinates and a radius.""" + ellipse_xy = (xy[0] - radius, xy[1] - radius, xy[0] + radius, xy[1] + radius) + self.ellipse(ellipse_xy, fill, outline, width) + def line(self, xy: Coords, fill=None, width=0, joint=None) -> None: """Draw a line, or a connected sequence of line segments.""" ink = self._getink(fill)[0]