pygame-ce icon indicating copy to clipboard operation
pygame-ce copied to clipboard

Add an example of filtering pre-installed fonts by language

Open gottadiveintopython opened this issue 1 year ago • 11 comments
trafficstars

This example demonstrates how to filter the pre-installed fonts on the system, by a language.

screenshot

gottadiveintopython avatar Nov 29 '23 04:11 gottadiveintopython

You need to run python setup.py format to format the code.

yunline avatar Nov 30 '23 07:11 yunline

I think we can make this work without freetype if we fix a bug in font.c

MyreMylar avatar Nov 30 '23 21:11 MyreMylar

Line 885 should have:

        if ((TTF_GlyphIsProvided(font, ch) != 0) &&

MyreMylar avatar Nov 30 '23 21:11 MyreMylar

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()

MyreMylar avatar Nov 30 '23 21:11 MyreMylar

@yunline @MyreMylar Thank you but I'm not familiar enough with PyGame nor SDL to modify its code, so I shouldn't do that.

gottadiveintopython avatar Dec 01 '23 12:12 gottadiveintopython

@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

MyreMylar avatar Dec 01 '23 17:12 MyreMylar

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 avatar Dec 02 '23 09:12 MyreMylar

@MyreMylar Thank you for clarification :) I'll rewrite the example without using the pygame.freetype module then. Maybe after #2593 is merged.

gottadiveintopython avatar Dec 03 '23 03:12 gottadiveintopython

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 avatar Dec 03 '23 04:12 Starbuck5

@Starbuck5 I feel like so.

gottadiveintopython avatar Dec 05 '23 13:12 gottadiveintopython

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.

gottadiveintopython avatar Feb 25 '24 09:02 gottadiveintopython