pygame-ce
pygame-ce copied to clipboard
Add an example of filtering pre-installed fonts by language
This example demonstrates how to filter the pre-installed fonts on the system, by a language.
You need to run python setup.py format to format the code.
I think we can make this work without freetype if we fix a bug in font.c
Line 885 should have:
if ((TTF_GlyphIsProvided(font, ch) != 0) &&
Then we can rewrite example to be:
"""
This example demonstrates how to find fonts for each language.
"""
from typing import Iterator
from pygame.font import get_fonts, SysFont
import pygame
def enum_font_from_lang(lang) -> Iterator[str]:
"""
Enumerates fonts that are suitable for a specified language.
"""
text = DISCRIMINANTS[lang]
for font_name in get_fonts():
if can_render_text(font_name, text):
yield font_name
def can_render_text(font_name, text, *, font_size=14) -> bool:
"""
Whether a specified font is capable of rendering a specified text.
"""
try:
font = SysFont(font_name, font_size)
except AttributeError as e:
# AttributeError occurs on certain fonts, which may be a PyGame bug.
if e.args[0] == r"this style is unsupported for a bitmap font":
return False
else:
raise
for c in text:
font_metrics = font.metrics(c)
print(font_name, c, font_metrics)
if None in font_metrics:
return False
return True
DISCRIMINANTS = {
"ja": "経伝説あAB",
"ko": "안녕조AB",
"zh-Hans": "哪经传说AB",
"zh-Hant": "哪經傳說AB",
"zh": "哪經傳說经传说AB",
}
"""
You may have noticed the 'AB' in the values of this dictionary.
If you don't include ASCII characters, you might choose a font that cannot render them, such as a fallback font,
which is probably not what you want.
"""
def main():
pygame.init()
screen = pygame.display.set_mode((800, 800))
screen.fill("white")
x, y = 40, 10
spacing = 10
for font_name in enum_font_from_lang("ja"):
font = SysFont(font_name, 30)
rendered_text = font.render(
"経伝説 한글 经传说 ABC 經傳說 あいう", True, pygame.Color("black")
).convert_alpha()
rect = rendered_text.get_rect()
rect.topleft = (x, y)
screen.blit(rendered_text, rect)
y = y + rect.height + spacing
pygame.display.flip()
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
running = False
clock.tick(4)
pygame.quit()
if __name__ == "__main__":
main()
@yunline @MyreMylar Thank you but I'm not familiar enough with PyGame nor SDL to modify its code, so I shouldn't do that.
@yunline @MyreMylar Thank you but I'm not familiar enough with PyGame nor SDL to modify its code, so I shouldn't do that.
No worries, I wasn't expecting you to solve this. I have along standing plan to gradually deprecate the freetype submodule so I will go to great lengths to keep it from expanding further throughout the codebase.
Anyway I made a PR to look at this issue in font further here:
https://github.com/pygame-community/pygame-ce/pull/2593
Just to be clear, there is a long running confusion over pygame/pygame-ce having multiple font handling submodules (font,freetype,sysfont, ftfont that all, have the 'freetype' library underlying them. There isn't a great reason for this, other than the fact that the pygame library has a long history and there were periods of time when one path or another made sense and then workarounds were added and so on.
What I would like is for pygame to have one clear user and developer story on handling fonts while wrapping the freetype library. In the present time, the font submodule looks like the best place to centralise because it leverages the work of SDL_ttf as well as our own efforts here. They recently solved the problem of rendering arabic alphabets correctly by integrating harfbuzz with freetype and the font module was able to quickly adopt those improvements.
Centralising will be a slow process of first making sure we can support all the use cases of the other submodules with code in font. This example here just triggered me to investigate why it couldn't be done entirely with font.
The documentation for the freetype module saying it is a replacement for font is both of it's time and also a true thing to say in that you can do most of the same things with either submodule (but not everything in either direction).
@MyreMylar Thank you for clarification :) I'll rewrite the example without using the pygame.freetype module then. Maybe after #2593 is merged.
We also have a draft PR that adds is_char_defined to Font. https://github.com/pygame-community/pygame-ce/pull/2178
If that feature lands would that become the preferred way of doing this?
@Starbuck5 I feel like so.
I might need to add more comments to the example if you merge it as is, such as
The result of can_render_text is not 100% accurate.