Skip to content

Commit 76254ed

Browse files
committed
Only use outside border of stroke in text()
1 parent cf7dd2f commit 76254ed

File tree

6 files changed

+42
-2
lines changed

6 files changed

+42
-2
lines changed

Tests/test_imagedraw.py

+22
Original file line numberDiff line numberDiff line change
@@ -1396,6 +1396,28 @@ def test_stroke_descender() -> None:
13961396
assert_image_similar_tofile(im, "Tests/images/imagedraw_stroke_descender.png", 6.76)
13971397

13981398

1399+
@skip_unless_feature("freetype2")
1400+
def test_stroke_inside_gap() -> None:
1401+
# Arrange
1402+
im = Image.new("RGB", (120, 130))
1403+
draw = ImageDraw.Draw(im)
1404+
font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120)
1405+
1406+
# Act
1407+
draw.text((12, 12), "i", "#f00", font, stroke_width=20)
1408+
1409+
# Assert
1410+
for y in range(im.height):
1411+
glyph = ""
1412+
for x in range(im.width):
1413+
if im.getpixel((x, y)) == (0, 0, 0):
1414+
if glyph == "started":
1415+
glyph = "ended"
1416+
else:
1417+
assert glyph != "ended", "Gap inside stroked glyph"
1418+
glyph = "started"
1419+
1420+
13991421
@skip_unless_feature("freetype2")
14001422
def test_split_word() -> None:
14011423
# Arrange

Tests/test_imagefont.py

+12
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,18 @@ def test_free_type_font_get_mask(font: ImageFont.FreeTypeFont) -> None:
461461
assert mask.size == (108, 13)
462462

463463

464+
def test_stroke_mask() -> None:
465+
# Arrange
466+
text = "mask this"
467+
468+
# Act
469+
font = ImageFont.truetype(FONT_PATH, 64)
470+
mask = font.getmask(text, stroke_width=1)
471+
472+
# Assert
473+
assert mask.size == (348, 43)
474+
475+
464476
def test_load_when_image_not_found() -> None:
465477
with tempfile.NamedTemporaryFile(delete=False) as tmp:
466478
pass

src/PIL/ImageDraw.py

+1
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@ def draw_text(ink: int, stroke_width: float = 0) -> None:
643643
features=features,
644644
language=language,
645645
stroke_width=stroke_width,
646+
stroke_filled=True,
646647
anchor=anchor,
647648
ink=ink,
648649
start=start,

src/PIL/ImageFont.py

+1
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ def fill(width: int, height: int) -> Image.core.ImagingCore:
644644
features,
645645
language,
646646
stroke_width,
647+
kwargs.get("stroke_filled", False),
647648
anchor,
648649
ink,
649650
start[0],

src/PIL/_imagingft.pyi

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class Font:
2828
features: list[str] | None,
2929
lang: str | None,
3030
stroke_width: float,
31+
stroke_filled: bool,
3132
anchor: str | None,
3233
foreground_ink_long: int,
3334
x_start: float,

src/_imagingft.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,7 @@ font_render(FontObject *self, PyObject *args) {
834834
int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
835835
int color = 0; /* is FT_LOAD_COLOR enabled? */
836836
float stroke_width = 0;
837+
int stroke_filled = 0;
837838
PY_LONG_LONG foreground_ink_long = 0;
838839
unsigned int foreground_ink;
839840
const char *mode = NULL;
@@ -853,14 +854,15 @@ font_render(FontObject *self, PyObject *args) {
853854

854855
if (!PyArg_ParseTuple(
855856
args,
856-
"OO|zzOzfzLffO:render",
857+
"OO|zzOzfpzLffO:render",
857858
&string,
858859
&fill,
859860
&mode,
860861
&dir,
861862
&features,
862863
&lang,
863864
&stroke_width,
865+
&stroke_filled,
864866
&anchor,
865867
&foreground_ink_long,
866868
&x_start,
@@ -1005,7 +1007,8 @@ font_render(FontObject *self, PyObject *args) {
10051007
if (stroker != NULL) {
10061008
error = FT_Get_Glyph(glyph_slot, &glyph);
10071009
if (!error) {
1008-
error = FT_Glyph_Stroke(&glyph, stroker, 1);
1010+
error = stroke_filled ? FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1)
1011+
: FT_Glyph_Stroke(&glyph, stroker, 1);
10091012
}
10101013
if (!error) {
10111014
FT_Vector origin = {0, 0};

0 commit comments

Comments
 (0)