mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 09:26: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
|
# Assert
|
||||||
self.assert_image_similar(im, Image.open(expected), 1)
|
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):
|
def test_textsize_empty_string(self):
|
||||||
# https://github.com/python-pillow/Pillow/issues/2783
|
# https://github.com/python-pillow/Pillow/issues/2783
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -171,19 +171,20 @@ Methods
|
||||||
:param outline: Color to use for the outline.
|
:param outline: Color to use for the outline.
|
||||||
:param fill: Color to use for the fill.
|
: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.
|
Draws a line between the coordinates in the **xy** list.
|
||||||
|
|
||||||
:param xy: Sequence of either 2-tuples like ``[(x, y), (x, y), ...]`` or
|
:param xy: Sequence of either 2-tuples like ``[(x, y), (x, y), ...]`` or
|
||||||
numeric values like ``[x, y, x, y, ...]``.
|
numeric values like ``[x, y, x, y, ...]``.
|
||||||
:param fill: Color to use for the line.
|
:param fill: Color to use for the line.
|
||||||
:param width: The line width, in pixels. Note that line
|
:param width: The line width, in pixels.
|
||||||
joins are not handled well, so wide polylines will not look good.
|
|
||||||
|
|
||||||
.. versionadded:: 1.1.5
|
.. versionadded:: 1.1.5
|
||||||
|
|
||||||
.. note:: This option was broken until version 1.1.6.
|
.. 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)
|
.. 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.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import math
|
||||||
import numbers
|
import numbers
|
||||||
|
|
||||||
from . import Image, ImageColor
|
from . import Image, ImageColor
|
||||||
|
@ -149,11 +150,64 @@ class ImageDraw(object):
|
||||||
if ink is not None and ink != fill:
|
if ink is not None and ink != fill:
|
||||||
self.draw.draw_ellipse(xy, ink, 0)
|
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."""
|
"""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:
|
if ink is not None:
|
||||||
self.draw.draw_lines(xy, ink, width)
|
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):
|
def shape(self, shape, fill=None, outline=None):
|
||||||
"""(Experimental) Draw a shape."""
|
"""(Experimental) Draw a shape."""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user