-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Draw font text line gap seems incorrect #6469
Comments
In css, the text draw is correct: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
@font-face {
font-family: Ark-Pixel-12px-latin;
src: url("ark-pixel-12px-latin.otf");
}
.content {
font-family: Ark-Pixel-12px-latin, serif;
font-size: 12px;
line-height: 12px; /* default is 12 */
}
</style>
</head>
<body>
<div class="content">
方舟像<br>素字体
</div>
</body>
</html> |
I view the src, found: https://github.com/python-pillow/Pillow/blob/9.2.0/src/PIL/ImageDraw.py#L377-L388 def _multiline_spacing(self, font, spacing, stroke_width):
# this can be replaced with self.textbbox(...)[3] when textsize is removed
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
return (
self.textsize(
"A",
font=font,
stroke_width=stroke_width,
)[1]
+ spacing
) is used by: https://github.com/python-pillow/Pillow/blob/9.2.0/src/PIL/ImageDraw.py#L529 It seems that self.textsize(
"A",
font=font,
stroke_width=stroke_width,
)[1] # <---- height
+ spacing I use the same font (ark-pixel-font-12px-otf): from PIL import ImageFont, Image, ImageDraw
if __name__ == '__main__':
font = ImageFont.truetype('build/outputs/ark-pixel-12px-latin.otf', 12)
image = Image.new('RGBA', (400, 400), (255, 255, 255))
draw = ImageDraw.Draw(image)
size_a = draw.textsize('A', font=font)
print(f'A: {size_a}')
size_fang = draw.textsize('方', font=font)
print(f'方: {size_fang}') or from PIL import ImageFont
if __name__ == '__main__':
font = ImageFont.truetype('build/outputs/ark-pixel-12px-latin.otf', 12)
size_a = font.getsize('A')
print(f'A: {size_a}')
size_fang = font.getsize('方')
print(f'方: {size_fang}') result:
|
Source-han-sans https://github.com/adobe-fonts/source-han-sans from PIL import ImageFont
if __name__ == '__main__':
font = ImageFont.truetype('build/outputs/SourceHanSansHW-Regular-SC.otf', 40)
size_a = font.getsize('A')
print(f'A: {size_a}')
size_fang = font.getsize('方')
print(f'方: {size_fang}') result height not equal
|
@nulano are you interested in answering this one? |
I'm going to call this a duplicate of #1646. I agree that the current method for calculating line height is subpar, but I'm not sure what is a good way to fix this without breaking backwards compatibility. Pillow uses FreeType internally to work with TrueType fonts. From FreeType documentation, the correct way to calculate the linespace (distance between two baselines) is However, as you found, Pillow calculates the linespace as the height of the letter A plus a user-specified >>> from PIL import ImageFont
>>> font = ImageFont.truetype(r"D:\Downloads\ark-pixel-font-12px-otf-v2022.07.05\ark-pixel-12px-latin.otf", 12)
>>> font.getmetrics()
(10, 2)
>>> font.getbbox("A") # no descender, bottom coordinate is the ascent height
(0, 2, 6, 10)
>>> font.getbbox("Q") # has descender, bottom coordinate is larger than ascent height
(0, 2, 6, 12) To get the expected results, for now you should pass from PIL import Image, ImageDraw, ImageFont
font = ImageFont.truetype(r"D:\Downloads\ark-pixel-font-12px-otf-v2022.07.05\ark-pixel-12px-latin.otf", 12)
im = Image.new("RGBA", (50, 50), "white")
draw = ImageDraw.Draw(im)
text = '\u65B9\u821F\u50CF\n\u7D20\u5B57\u4F53'
line_height = font.getbbox("A")[3]
line_gap = 0 # looked up elsewhere
linespace = sum(font.getmetrics(), line_gap)
spacing = linespace - line_height
print(spacing) # 2
bbox = draw.textbbox((0, 0), text, font=font, spacing=spacing)
print(bbox) # (0, 1, 36, 24)
draw.text((0, 0), text, fill="black", font=font, spacing=spacing)
im.save(r"D:\Downloads\ark-pixel-font-12px-otf-v2022.07.05\test.png") Note that the bottom value of |
The clear fix code, I verified it is worked. ascent, descent = font.getmetrics()
line_gap = 0 # need to be set manually
line_height = ascent + descent + line_gap # the correct way
spacing = line_height - font.getsize('A')[1]
Will the apis keeps for a long time? Otherwise we can just fix like: def _multiline_spacing(self, font, spacing, stroke_width):
return sum(font.getmetrics(), spacing) Although we are still lost font line_gap, but at least can set spacing, just the name different. |
I have just looked at the FreeType API and it seems not to expose However, the parameter
This value is also not exposed by Pillow publically, but it is available via the private parameter >>> font.font.height
12 |
Yes. This is documented in the documentation of getsize():
And also noted in a comment in the source code: Lines 377 to 388 in 7591395
Similarly, |
Thanks @nulano for your thoughts |
Python: 3.9
Pillow: 9.2.0
I use this font: ark-pixel-font-12px-otf v2022.07.05
https://github.com/TakWolf/ark-pixel-font/releases
The font has zero line_gap:
font_size = 12
upm = 1200
line_height = 1200 (ascent - descent)
line_gap = 0
(xml gen use https://github.com/fonttools/fonttools ttx tools)
and
In pillow:
Actually there is -2 line_gap
result:
The text was updated successfully, but these errors were encountered: