Fix punctuation glyph overlap and line-end clipping
PIL draws full-width punctuation offset inside the advance box (e.g. left bracket '(' ink sits at x+42..x+61 while its advance is only 0.45em), so the next glyph overlapped it and a trailing bracket could clip. Shift the draw x by the ink offset for narrow punctuation and add right padding so line ends never clip. Verified: bracket gap restored, line end intact.
This commit is contained in:
1 parent
4fcc5acc85
commit
d322404e5a
1 file changed
+16
-3
+16
-3
@@ -339,13 +339,25 @@ def render_text(ly: dict, cw: int, ch: int) -> Optional[Tuple[Image.Image, Tuple
|
|||||||
# faux bold (textFontStyle=1) via stroke width
|
# faux bold (textFontStyle=1) via stroke width
|
||||||
stroke_w = max(1, int(size / 40)) if ly.get("textFontStyle") == "1" else 0
|
stroke_w = max(1, int(size / 40)) if ly.get("textFontStyle") == "1" else 0
|
||||||
pad = stroke_w # room for the stroke so glyphs don't clip
|
pad = stroke_w # room for the stroke so glyphs don't clip
|
||||||
raw_w, raw_h = max(1, int(round(tw)) + 2 * pad), max(1, int(round(th)) + 2 * pad)
|
tail = max(int(size * 0.3), 8) # right padding so the last glyph never clips
|
||||||
|
raw_w, raw_h = max(1, int(round(tw)) + 2 * pad + tail), max(1, int(round(th)) + 2 * pad)
|
||||||
img = Image.new("RGBA", (raw_w, raw_h), (0, 0, 0, 0))
|
img = Image.new("RGBA", (raw_w, raw_h), (0, 0, 0, 0))
|
||||||
draw = ImageDraw.Draw(img)
|
draw = ImageDraw.Draw(img)
|
||||||
for i, ln in enumerate(lines):
|
for i, ln in enumerate(lines):
|
||||||
x = pad
|
x = pad
|
||||||
for ch_ in ln:
|
for ch_ in ln:
|
||||||
draw.text((x, pad + int(round(i * line_h))), ch_, font=font,
|
off = 0
|
||||||
|
if ch_ in NARROW_PUNCT:
|
||||||
|
# PIL draws full-width punctuation offset inside the advance
|
||||||
|
# box (e.g. '(' ink sits at x+42..x+61). Shift the draw x so
|
||||||
|
# the ink starts at the layout x; otherwise it overlaps the
|
||||||
|
# next glyph or clips at line end.
|
||||||
|
t_img = Image.new("RGBA", (int(size) + 16, int(size) + 16), (0, 0, 0, 0))
|
||||||
|
ImageDraw.Draw(t_img).text((4, 4), ch_, font=font,
|
||||||
|
fill=(255, 255, 255, 255))
|
||||||
|
t_bb = t_img.getchannel("A").getbbox()
|
||||||
|
off = t_bb[0] - 4 if t_bb else 0
|
||||||
|
draw.text((x - off, pad + int(round(i * line_h))), ch_, font=font,
|
||||||
fill=fill, stroke_width=stroke_w, stroke_fill=fill)
|
fill=fill, stroke_width=stroke_w, stroke_fill=fill)
|
||||||
x += char_advance(ch_) + ls
|
x += char_advance(ch_) + ls
|
||||||
|
|
||||||
@@ -355,7 +367,8 @@ def render_text(ly: dict, cw: int, ch: int) -> Optional[Tuple[Image.Image, Tuple
|
|||||||
# export for the title layers).
|
# export for the title layers).
|
||||||
cx, cy = (l + r) / 2, (t + b) / 2
|
cx, cy = (l + r) / 2, (t + b) / 2
|
||||||
if prof.get("narrow"):
|
if prof.get("narrow"):
|
||||||
left_full = int(round(cx - raw_w / 2))
|
# center on the advance width (excluding the clip-padding tail)
|
||||||
|
left_full = int(round(cx - (tw + 2 * pad) / 2))
|
||||||
top_full = int(round(cy - raw_h / 2))
|
top_full = int(round(cy - raw_h / 2))
|
||||||
content = img.getchannel("A").getbbox()
|
content = img.getchannel("A").getbbox()
|
||||||
if content:
|
if content:
|
||||||
|
|||||||
Reference in new issue
Block a user