2

I'm trying to check if a font has a glyph for a multi codepoint emoji like "‍♂️", "‍" or "" in Python 3.x.

For single codepoint emoji like "" or "" I'm able to validate their support via the following code using Python fonttols:

from fontTools.ttLib import TTFont

def __isEmojiSupportedByFont(emoji: str) -> bool:
    font = TTFont(r"C:\Windows\Fonts\seguiemj.ttf")
    emojiCodepoint = ord(str) # Only works for single codepoint emoji
    for table in font['cmap'].tables:
        for char_code, glyph_name in table.cmap.items():
            if char_code == emojiCodepoint:
                return True
    return False

How do I do this for multi codepoint emoji, since the cmp only has single codepoint emoji in it?

COM8
  • 271
  • 1
  • 10

1 Answers1

1

To check for multi codepoint emoji I would have to "query" the GSUB Lookup List.

An easier way to check if an Emoji is supported by a font in python is to use HarfBuzz or more exact harfpy.

The solution I came up with is:

from uharfbuzz import Face, Font, Buffer, ot_font_set_funcs, shape

def __isEmojiSupportedByFont(self, emoji: str) -> bool:
    # Load font:
    with open(r"C:\Windows\Fonts\seguiemj.ttf", 'rb') as fontfile:
        self.fontdata = fontfile.read()

    # Load font (has to be done for call):
    face = Face(self.fontdata)
    font = Font(face)
    upem = face.upem
    font.scale = (upem, upem)
    ot_font_set_funcs(font)

    # Create text buffer:
    buf = Buffer()
    buf.add_str(emoji)
    buf.guess_segment_properties()

    # Shape text:
    features = {"kern": True, "liga": True}
    shape(font, buf, features)

    # Remove all variant selectors:
    while len(infos) > 0 and infos[-1].codepoint == 3:
        infos = infos[:-1]

    # Filter empty:
    if len(infos) <= 0:
        return False

    # Remove uncombined, ending with skin tone like "":
    lastCp = infos[-1].codepoint
    if lastCp == 1076 or lastCp == 1079 or lastCp == 1082 or lastCp == 1085 or lastCp == 1088:
        return False

    # If there is a code point 0 or 3 => Emoji not fully supported by font:
    return all(info.codepoint != 0 and info.codepoint != 3 for info in infos)

Thanks to khaledhosny and justvanrossum over on GitHub/fonttols!

COM8
  • 271
  • 1
  • 10
  • Where did you get the codepoints 1076, 1079, 1082, 1085, 1088? They don't correspond to the skin tone points 1F3FB-1F3FF – jdaz Jun 21 '20 at 23:36