mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-27 18:36:17 +03:00
Merge pull request #5208 from radarhere/rounded_rectangle
This commit is contained in:
commit
02ed076968
BIN
Tests/images/imagedraw_rounded_rectangle.png
Normal file
BIN
Tests/images/imagedraw_rounded_rectangle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 934 B |
BIN
Tests/images/imagedraw_rounded_rectangle_both.png
Normal file
BIN
Tests/images/imagedraw_rounded_rectangle_both.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 530 B |
BIN
Tests/images/imagedraw_rounded_rectangle_x.png
Normal file
BIN
Tests/images/imagedraw_rounded_rectangle_x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 567 B |
BIN
Tests/images/imagedraw_rounded_rectangle_y.png
Normal file
BIN
Tests/images/imagedraw_rounded_rectangle_y.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 528 B |
|
@ -706,6 +706,58 @@ def test_rectangle_translucent_outline():
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xy",
|
||||
[(10, 20, 190, 180), ([10, 20], [190, 180]), ((10, 20), (190, 180))],
|
||||
)
|
||||
def test_rounded_rectangle(xy):
|
||||
# Arrange
|
||||
im = Image.new("RGB", (200, 200))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
||||
# Act
|
||||
draw.rounded_rectangle(xy, 30, fill="red", outline="green", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_equal_tofile(im, "Tests/images/imagedraw_rounded_rectangle.png")
|
||||
|
||||
|
||||
def test_rounded_rectangle_zero_radius():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
||||
# Act
|
||||
draw.rounded_rectangle(BBOX1, 0, fill="blue", outline="green", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle_width_fill.png")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"xy, suffix",
|
||||
[
|
||||
((20, 10, 80, 90), "x"),
|
||||
((10, 20, 90, 80), "y"),
|
||||
((20, 20, 80, 80), "both"),
|
||||
],
|
||||
)
|
||||
def test_rounded_rectangle_translucent(xy, suffix):
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im, "RGBA")
|
||||
|
||||
# Act
|
||||
draw.rounded_rectangle(
|
||||
xy, 30, fill=(255, 0, 0, 127), outline=(0, 255, 0, 127), width=5
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert_image_equal_tofile(
|
||||
im, "Tests/images/imagedraw_rounded_rectangle_" + suffix + ".png"
|
||||
)
|
||||
|
||||
|
||||
def test_floodfill():
|
||||
red = ImageColor.getrgb("red")
|
||||
|
||||
|
|
|
@ -285,6 +285,20 @@ Methods
|
|||
|
||||
.. versionadded:: 5.3.0
|
||||
|
||||
.. py:method:: ImageDraw.rounded_rectangle(xy, radius=0, fill=None, outline=None, width=1)
|
||||
|
||||
Draws a rounded rectangle.
|
||||
|
||||
:param xy: Two points to define the bounding box. Sequence of either
|
||||
``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``. The second point
|
||||
is just outside the drawn rectangle.
|
||||
:param radius: Radius of the corners.
|
||||
:param outline: Color to use for the outline.
|
||||
:param fill: Color to use for the fill.
|
||||
:param width: The line width, in pixels.
|
||||
|
||||
.. versionadded:: 8.2.0
|
||||
|
||||
.. py:method:: ImageDraw.shape(shape, fill=None, outline=None)
|
||||
|
||||
.. warning:: This method is experimental.
|
||||
|
|
|
@ -13,10 +13,20 @@ when Tk/Tcl 8.5 will be the minimum supported.
|
|||
API Changes
|
||||
===========
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
ImageDraw.rounded_rectangle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
TODO
|
||||
Added :py:meth:`~PIL.ImageDraw.ImageDraw.rounded_rectangle`. It works the same as
|
||||
:py:meth:`~PIL.ImageDraw.ImageDraw.rectangle`, except with an additional ``radius``
|
||||
argument. ``radius`` is limited to half of the width or the height, so that users can
|
||||
create a circle, but not any other ellipse.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
im = Image.new("RGB", (200, 200))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.rounded_rectangle(xy=(10, 20, 190, 180), radius=30, fill="red")
|
||||
|
||||
API Additions
|
||||
=============
|
||||
|
|
|
@ -257,6 +257,96 @@ class ImageDraw:
|
|||
if ink is not None and ink != fill and width != 0:
|
||||
self.draw.draw_rectangle(xy, ink, 0, width)
|
||||
|
||||
def rounded_rectangle(self, xy, radius=0, fill=None, outline=None, width=1):
|
||||
"""Draw a rounded rectangle."""
|
||||
if isinstance(xy[0], (list, tuple)):
|
||||
(x0, y0), (x1, y1) = xy
|
||||
else:
|
||||
x0, y0, x1, y1 = xy
|
||||
|
||||
d = radius * 2
|
||||
|
||||
full_x = d >= x1 - x0
|
||||
if full_x:
|
||||
# The two left and two right corners are joined
|
||||
d = x1 - x0
|
||||
full_y = d >= y1 - y0
|
||||
if full_y:
|
||||
# The two top and two bottom corners are joined
|
||||
d = y1 - y0
|
||||
if full_x and full_y:
|
||||
# If all corners are joined, that is a circle
|
||||
return self.ellipse(xy, fill, outline, width)
|
||||
|
||||
if d == 0:
|
||||
# If the corners have no curve, that is a rectangle
|
||||
return self.rectangle(xy, fill, outline, width)
|
||||
|
||||
ink, fill = self._getink(outline, fill)
|
||||
|
||||
def draw_corners(pieslice):
|
||||
if full_x:
|
||||
# Draw top and bottom halves
|
||||
parts = (
|
||||
((x0, y0, x0 + d, y0 + d), 180, 360),
|
||||
((x0, y1 - d, x0 + d, y1), 0, 180),
|
||||
)
|
||||
elif full_y:
|
||||
# Draw left and right halves
|
||||
parts = (
|
||||
((x0, y0, x0 + d, y0 + d), 90, 270),
|
||||
((x1 - d, y0, x1, y0 + d), 270, 90),
|
||||
)
|
||||
else:
|
||||
# Draw four separate corners
|
||||
parts = (
|
||||
((x1 - d, y0, x1, y0 + d), 270, 360),
|
||||
((x1 - d, y1 - d, x1, y1), 0, 90),
|
||||
((x0, y1 - d, x0 + d, y1), 90, 180),
|
||||
((x0, y0, x0 + d, y0 + d), 180, 270),
|
||||
)
|
||||
for part in parts:
|
||||
if pieslice:
|
||||
self.draw.draw_pieslice(*(part + (fill, 1)))
|
||||
else:
|
||||
self.draw.draw_arc(*(part + (ink, width)))
|
||||
|
||||
if fill is not None:
|
||||
draw_corners(True)
|
||||
|
||||
if full_x:
|
||||
self.draw.draw_rectangle(
|
||||
(x0, y0 + d / 2 + 1, x1, y1 - d / 2 - 1), fill, 1
|
||||
)
|
||||
else:
|
||||
self.draw.draw_rectangle(
|
||||
(x0 + d / 2 + 1, y0, x1 - d / 2 - 1, y1), fill, 1
|
||||
)
|
||||
if not full_x and not full_y:
|
||||
self.draw.draw_rectangle(
|
||||
(x0, y0 + d / 2 + 1, x0 + d / 2, y1 - d / 2 - 1), fill, 1
|
||||
)
|
||||
self.draw.draw_rectangle(
|
||||
(x1 - d / 2, y0 + d / 2 + 1, x1, y1 - d / 2 - 1), fill, 1
|
||||
)
|
||||
if ink is not None and ink != fill and width != 0:
|
||||
draw_corners(False)
|
||||
|
||||
if not full_x:
|
||||
self.draw.draw_rectangle(
|
||||
(x0 + d / 2 + 1, y0, x1 - d / 2 - 1, y0 + width - 1), ink, 1
|
||||
)
|
||||
self.draw.draw_rectangle(
|
||||
(x0 + d / 2 + 1, y1 - width + 1, x1 - d / 2 - 1, y1), ink, 1
|
||||
)
|
||||
if not full_y:
|
||||
self.draw.draw_rectangle(
|
||||
(x0, y0 + d / 2 + 1, x0 + width - 1, y1 - d / 2 - 1), ink, 1
|
||||
)
|
||||
self.draw.draw_rectangle(
|
||||
(x1 - width + 1, y0 + d / 2 + 1, x1, y1 - d / 2 - 1), ink, 1
|
||||
)
|
||||
|
||||
def _multiline_check(self, text):
|
||||
"""Draw text."""
|
||||
split_character = "\n" if isinstance(text, str) else b"\n"
|
||||
|
|
Loading…
Reference in New Issue
Block a user