mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 17:06:16 +03:00
Added line joints
This commit is contained in:
parent
74f5007bf1
commit
f3842460ba
BIN
Tests/images/imagedraw_line_joint_curve.png
Normal file
BIN
Tests/images/imagedraw_line_joint_curve.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
|
@ -568,6 +568,20 @@ class TestImageDraw(PillowTestCase):
|
|||
# Assert
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
||||
def test_line_joint(self):
|
||||
im = Image.new("RGB", (500, 325))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_line_joint_curve.png"
|
||||
|
||||
# Act
|
||||
xy = [(400, 280), (380, 280), (450, 280), (440, 120), (350, 200),
|
||||
(310, 280), (300, 280), (250, 280), (250, 200), (150, 200),
|
||||
(150, 260), (50, 200), (150, 50), (250, 100)]
|
||||
draw.line(xy, GRAY, 50, "curve")
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(im, Image.open(expected), 3)
|
||||
|
||||
def test_textsize_empty_string(self):
|
||||
# https://github.com/python-pillow/Pillow/issues/2783
|
||||
# Arrange
|
||||
|
|
|
@ -171,19 +171,20 @@ Methods
|
|||
:param outline: Color to use for the outline.
|
||||
:param fill: Color to use for the fill.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.line(xy, fill=None, width=0)
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.line(xy, fill=None, width=0, joint=None)
|
||||
|
||||
Draws a line between the coordinates in the **xy** list.
|
||||
|
||||
:param xy: Sequence of either 2-tuples like ``[(x, y), (x, y), ...]`` or
|
||||
numeric values like ``[x, y, x, y, ...]``.
|
||||
:param fill: Color to use for the line.
|
||||
:param width: The line width, in pixels. Note that line
|
||||
joins are not handled well, so wide polylines will not look good.
|
||||
:param width: The line width, in pixels.
|
||||
|
||||
.. versionadded:: 1.1.5
|
||||
|
||||
.. note:: This option was broken until version 1.1.6.
|
||||
:param joint: Joint type between a sequence of lines. It can be "curve",
|
||||
for rounded edges, or None.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.pieslice(xy, start, end, fill=None, outline=None)
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
import math
|
||||
import numbers
|
||||
|
||||
from . import Image, ImageColor
|
||||
|
@ -149,11 +150,64 @@ class ImageDraw(object):
|
|||
if ink is not None and ink != fill:
|
||||
self.draw.draw_ellipse(xy, ink, 0)
|
||||
|
||||
def line(self, xy, fill=None, width=0):
|
||||
def line(self, xy, fill=None, width=0, joint=None):
|
||||
"""Draw a line, or a connected sequence of line segments."""
|
||||
ink, fill = self._getink(fill)
|
||||
ink = self._getink(fill)[0]
|
||||
if ink is not None:
|
||||
self.draw.draw_lines(xy, ink, width)
|
||||
if joint == "curve" and width > 4:
|
||||
for i in range(1, len(xy)-1):
|
||||
point = xy[i]
|
||||
angles = [
|
||||
math.degrees(math.atan2(
|
||||
end[0] - start[0], start[1] - end[1]
|
||||
)) % 360
|
||||
for start, end in ((xy[i-1], point), (point, xy[i+1]))
|
||||
]
|
||||
if angles[0] == angles[1]:
|
||||
# This is a straight line, so no joint is required
|
||||
continue
|
||||
|
||||
def coord_at_angle(coord, angle):
|
||||
x, y = coord
|
||||
angle -= 90
|
||||
distance = width/2 - 1
|
||||
return tuple([
|
||||
p +
|
||||
(math.floor(p_d) if p_d > 0 else math.ceil(p_d))
|
||||
for p, p_d in
|
||||
((x, distance * math.cos(math.radians(angle))),
|
||||
(y, distance * math.sin(math.radians(angle))))
|
||||
])
|
||||
flipped = ((angles[1] > angles[0] and
|
||||
angles[1] - 180 > angles[0]) or
|
||||
(angles[1] < angles[0] and
|
||||
angles[1] + 180 > angles[0]))
|
||||
coords = [
|
||||
(point[0] - width/2 + 1, point[1] - width/2 + 1),
|
||||
(point[0] + width/2 - 1, point[1] + width/2 - 1)
|
||||
]
|
||||
if flipped:
|
||||
start, end = (angles[1] + 90, angles[0] + 90)
|
||||
else:
|
||||
start, end = (angles[0] - 90, angles[1] - 90)
|
||||
self.pieslice(coords, start - 90, end - 90, fill)
|
||||
|
||||
if width > 8:
|
||||
# Cover potential gaps between the line and the joint
|
||||
if flipped:
|
||||
gapCoords = [
|
||||
coord_at_angle(point, angles[0]+90),
|
||||
point,
|
||||
coord_at_angle(point, angles[1]+90)
|
||||
]
|
||||
else:
|
||||
gapCoords = [
|
||||
coord_at_angle(point, angles[0]-90),
|
||||
point,
|
||||
coord_at_angle(point, angles[1]-90)
|
||||
]
|
||||
self.line(gapCoords, fill, width=3)
|
||||
|
||||
def shape(self, shape, fill=None, outline=None):
|
||||
"""(Experimental) Draw a shape."""
|
||||
|
|
Loading…
Reference in New Issue
Block a user