Skip to content
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

Add an example of filtering pre-installed fonts by language #2592

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

gottadiveintopython
Copy link

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

screenshot

@gottadiveintopython gottadiveintopython requested a review from a team as a code owner November 29, 2023 04:21
@gottadiveintopython gottadiveintopython changed the title Add font filtering example Add an example of filtering pre-installed fonts Nov 29, 2023
@gottadiveintopython gottadiveintopython changed the title Add an example of filtering pre-installed fonts Add an example of filtering pre-installed fonts by language Nov 29, 2023
@yunline
Copy link
Contributor

yunline commented Nov 30, 2023

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

@MyreMylar
Copy link
Member

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

@MyreMylar
Copy link
Member

Line 885 should have:

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

@MyreMylar
Copy link
Member

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

@gottadiveintopython
Copy link
Author

gottadiveintopython commented Dec 1, 2023

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

@MyreMylar
Copy link
Member

@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:

#2593

@MyreMylar
Copy link
Member

MyreMylar commented Dec 2, 2023

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

@gottadiveintopython
Copy link
Author

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

@Starbuck5
Copy link
Member

We also have a draft PR that adds is_char_defined to Font. #2178

If that feature lands would that become the preferred way of doing this?

@gottadiveintopython
Copy link
Author

@Starbuck5 I feel like so.

Copy link
Member

@MyreMylar MyreMylar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example itself seems fine but is awaiting another PR. Should we merge it as is anyway?

@gottadiveintopython
Copy link
Author

gottadiveintopython commented Feb 25, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants