Python ImageFont and ImageDraw check font for character support
Asked Answered
G

2

11

I am using Python's image processing libraries to render images of characters using different fonts.

Here's a snippet of the code that I'm using to iterate through a list of fonts and a list of characters to output an image of that character for each font.

from PIL import Image, ImageFont, ImageDraw
...

image = Image.new('L', (IMAGE_WIDTH, IMAGE_HEIGHT), color=0)
font = ImageFont.truetype(font, 48)
drawing = ImageDraw.Draw(image)
w, h = drawing.textsize(character, font=font)
drawing.text(
            ((IMAGE_WIDTH-w)/2, (IMAGE_HEIGHT-h)/2),
            character,
            fill=(255),
            font=font
)

However, in some cases, the font doesn't support a character and renders either a black image or a default/invalid character. How can I detect that the character isn't supported by a font and handle that case separately?

Germano answered 23/12, 2017 at 0:41 Comment(0)
Y
11

You can use the fontTools library to achieve this:

from fontTools.ttLib import TTFont
from fontTools.unicode import Unicode

font = TTFont('/path/to/font.ttf')

def has_glyph(font, glyph):
    for table in font['cmap'].tables:
        if ord(glyph) in table.cmap.keys():
            return True
    return False

This function returns whether a character is contained in a font or not:

>>> has_glyph(font, 'a')
True
>>> has_glyph(font, 'Ä')
True
>>> chr(0x1f603)
'😃'
>>> has_glyph(font, chr(0x1f603))
False
Yenyenisei answered 18/12, 2018 at 8:57 Comment(0)
I
0

I had to use another method because sometime the glyph exists but with a size of 0. Here's the code:

from PIL import ImageFont

letter_list = [
    "%", ':', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
    'x', 'y', 'z',
]


def check_font_is_complete(font_path: str, font_folder: str) -> bool:
    if font_path.lower().endswith('.ttf'):
        font = ImageFont.truetype(font_folder + font_path, 24)
    else:
        return False

    for a_letter in letter_list:
        left, top, right, bottom = font.getbbox(a_letter)
        if left == right or top == bottom:
            return False

    return True
Inquisitorial answered 21/6 at 10:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.