Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a feature to ImageDraw.text() to stroke text #2224

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 12 additions & 7 deletions PIL/ImageDraw.py
Expand Up @@ -217,12 +217,11 @@ def _multiline_split(self, text):

return text.split(split_character)

def text(self, xy, text, fill=None, font=None, anchor=None,
*args, **kwargs):
def text(self, xy, text, fill=None, font=None, anchor=None, spacing=4,
align="left", outline=None):
if self._multiline_check(text):
return self.multiline_text(xy, text, fill, font, anchor,
*args, **kwargs)

spacing, align, outline)
ink, fill = self._getink(fill)
if font is None:
font = self.getfont()
Expand All @@ -237,10 +236,17 @@ def text(self, xy, text, fill=None, font=None, anchor=None,
mask = font.getmask(text, self.fontmode)
except TypeError:
mask = font.getmask(text)
if outline is not None:
color, _ = self._getink(outline)
for offset in range(0, 2):
tmp_xy = list(xy)
for difference in [-1, 1]:
tmp_xy[offset] = xy[offset] + difference
self.draw.draw_bitmap(tmp_xy, mask, color)
self.draw.draw_bitmap(xy, mask, ink)

def multiline_text(self, xy, text, fill=None, font=None, anchor=None,
spacing=4, align="left"):
spacing=4, align="left", outline=None):
widths = []
max_width = 0
lines = self._multiline_split(text)
Expand All @@ -259,10 +265,9 @@ def multiline_text(self, xy, text, fill=None, font=None, anchor=None,
left += (max_width - widths[idx])
else:
assert False, 'align must be "left", "center" or "right"'
self.text((left, top), line, fill, font, anchor)
self.text((left, top), line, fill, font, anchor, outline=outline)
top += line_spacing
left = xy[0]

def textsize(self, text, font=None, *args, **kwargs):
"""Get the size of a given string, in pixels."""
if self._multiline_check(text):
Expand Down
Binary file added Tests/images/stroked_text_image.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions Tests/test_imagefont.py
Expand Up @@ -127,6 +127,18 @@ def test_textsize_equal(self):
target_img = Image.open(target)
self.assert_image_similar(im, target_img, .5)

def test_stroke_text(self):
im = Image.new(mode='RGB', size=(300, 100))
draw = ImageDraw.Draw(im)
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)

draw.text((5, 5), TEST_TEXT, 'black', font=ttf,
outline='white')

target = 'Tests/images/stroked_text_image.png'
target_img = Image.open(target)
self.assert_image_similar(im, target_img, .5)

def test_render_multiline(self):
im = Image.new(mode='RGB', size=(300, 100))
draw = ImageDraw.Draw(im)
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/ImageDraw.rst
Expand Up @@ -240,6 +240,7 @@ Methods
the number of pixels between lines.
:param align: If the text is passed on to multiline_text(),
"left", "center" or "right".
:param outline: Color to use to draw an outline around the text.


.. py:method:: PIL.ImageDraw.Draw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left")
Expand All @@ -252,6 +253,7 @@ Methods
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
:param spacing: The number of pixels between lines.
:param align: "left", "center" or "right".
:param outline: Color to use to draw an outline around the text.

.. py:method:: PIL.ImageDraw.Draw.textsize(text, font=None, spacing=0)

Expand Down
10 changes: 10 additions & 0 deletions docs/releasenotes/3.5.0.rst
@@ -0,0 +1,10 @@
3.5.0
-----

New text-outlining feature
==========================

Both ``ImageDraw.text()`` and ``ImageDraw.multiline_text()`` now supports
text-stroking.
Passing in a color value to the methods using the ``outline`` keyword argument
will now outline the text in that color.
1 change: 1 addition & 0 deletions docs/releasenotes/index.rst
Expand Up @@ -6,6 +6,7 @@ Release Notes
.. toctree::
:maxdepth: 2

3.5.0
3.4.0
3.3.2
3.3.0
Expand Down