Skip to content Skip to sidebar Skip to footer

How To Determine If A Glyph Can Be Displayed?

I have a large list of Unicode icons that I want to display. However, I would like to hide/skip any icon that I cannot display (because I don't have the correct font installed). Is

Solution 1:

There's nothing built into Python for this. However, you can apply the fonttools module e.g. as follows (used in Windows 10):

# ToDo: find fallback font# ToDo: reverse algorithm (font => characters) instead of (character => fonts)# ToDo: check/print merely basic font (omit variants like Bold, Light, Condensed, …)import unicodedata
import sys
import os
from fontTools.ttLib import TTFont, TTCollection

fontsPaths = []
fontcPaths = []
fontsdirs = [ os.path.join( os.getenv('SystemRoot'), 'Fonts') # r"c:\Windows\Fonts"
              , r"D:\Downloads\MathJax-TeX-fonts-otf"# , os.path.join( os.getenv('LOCALAPPDATA'), r'Microsoft\Windows\Fonts')
              ]

print(fontsdirs, file=sys.stderr)
for fontsdir in fontsdirs:
    for root,dirs,files in os.walk( fontsdir ):
      for file in files:
        if file.endswith(".ttf") or file.endswith(".otf") or file.endswith(".ttc"):
          tfile = os.path.join(root,file)
          if file.endswith(".ttc"):
            fontcPaths.append(tfile)
          else:
            fontsPaths.append(tfile)
    # print( len(fonts), "fonts", fontsdir)defchar_in_font(unicode_char, font):
  for cmap in font['cmap'].tables:
    if cmap.isUnicode() or cmap.getEncoding() == 'utf_16_be':
      iford(unicode_char) in cmap.cmap:
        # print(type(cmap))
        auxcn =  cmap.cmap[ord(unicode_char)]
        # print(auxcn, type(auxcn))return auxcn if auxcn != ''else'<nil>'return''defcheckfont(char,font,fontdict,fontpath):
    nameID_index = 1# works generally (not always)for i,f inenumerate(font['name'].names):
        # An Introduction to TrueType Fonts: A look inside the TTF format# https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=IWS-Chapter08# 1 = Font Family name, 2 = Font SubFamily name, 4 = Full font nameif f.nameID == 1:
            nameID_index = i
            break
    fontname = font['name'].names[nameID_index].toStr()
    if fontname notin fontdict.keys():
        aux = char_in_font(char, font)
        if aux != '':
          fontdict[fontname] = "{} ({}) [{}] '{}' \t {} {}".format(
            char,
            '0x{:04x}'.format(ord(char)),
            aux,
            fontname, # string.decode('unicode-escape'),# '', '' 'in', fontpath.split('\\')[-1]
           )

deftestfont(char):
    fontdict = {}
    for fontpath in fontsPaths:
        font = TTFont(fontpath)   # specify the path to the font
        checkfont(char,font,fontdict,fontpath)
    for fontpath in fontcPaths:   # specify the path to the font collection
        fonts = TTCollection(fontpath)
        for ii inrange(len(fonts)):
          font = TTFont(fontpath, fontNumber=ii)   # fontfile and index 
          checkfont(char,font,fontdict,fontpath)
    return fontdict.values()

deftestprint(char):
    print('') # empty line for better readabilityprint(char, ' 0x{:04x}'.format(ord(char)), unicodedata.name(char, '???'))
    fontarray = testfont(char)
    for x in fontarray:
        print(x)

iflen(sys.argv) == 1:
    # sample output
    testprint(u"เค…")      # 0x0905 Devanagari Letter Aelse:
    for i inrange( 1, len(sys.argv) ):
        iflen(sys.argv[i]) >=2:
          try:
            chars =  chr(int(sys.argv[i]))      # 0x042F or 1071except:
            try:
              chars =  chr(int(sys.argv[i],16)) # 042Fexcept:
              chars = (sys.argv[i].
                encode('raw_unicode_escape').
                decode('unicode_escape'))       # ➕๐Ÿˆ\U00010A30\u042F\xFEelse:
            chars = sys.argv[i]                 # ะฏ (Cyrillic Capital Letter Ya)for char in chars:
            testprint(char);

Sample output (if called without arguments): .\FontGlyphs.py

['C:\\WINDOWS\\Fonts', 'D:\\Downloads\\MathJax-TeX-fonts-otf']

เค…  0x0905 DEVANAGARI LETTER A
เค… (0x0905) [uni0905] 'Nirmala UI'in Nirmala.ttf
เค… (0x0905) [uni0905] 'Nirmala UI Semilight'in NirmalaS.ttf
เค… (0x0905) [uni0905] 'Unifont'in unifont-8.0.01.ttf
เค… (0x0905) [uni0905] 'Unifont CSUR'in unifont_csur-8.0.01.ttf

Another example: .\FontGlyphs.py ๐Ÿˆ

['C:\\WINDOWS\\Fonts', 'D:\\Downloads\\MathJax-TeX-fonts-otf']

๐Ÿˆ  0x1f408CAT
๐Ÿˆ (0x1f408) [u1F408] 'EmojiOne Color'in EmojiOneColor-SVGinOT.ttf
๐Ÿˆ (0x1f408) [u1F408] 'Segoe UI Emoji'in seguiemj.ttf
๐Ÿˆ (0x1f408) [u1F408] 'Segoe UI Symbol'in seguisym.ttf

FYI, I have written similar script that shows output (glyphs) rendered using appropriate fonts (using default browser…

Limitation the script does not recognize Emoji Sequence, for instance

.\FontGlyphs.py ๐Ÿ‘๐Ÿฝ

['C:\\WINDOWS\\Fonts', 'D:\\Downloads\\MathJax-TeX-fonts-otf']

๐Ÿ‘  0x1f44d THUMBS UP SIGN
๐Ÿ‘ (0x1f44d) [u1F44D] 'EmojiOne Color'in EmojiOneColor-SVGinOT.ttf
๐Ÿ‘ (0x1f44d) [u1F44D] 'Segoe UI Emoji'in seguiemj.ttf
๐Ÿ‘ (0x1f44d) [u1F44D] 'Segoe UI Symbol'in seguisym.ttf

๐Ÿฝ  0x1f3fd EMOJI MODIFIER FITZPATRICK TYPE-4
๐Ÿฝ (0x1f3fd) [u1F3FD] 'EmojiOne Color'in EmojiOneColor-SVGinOT.ttf
๐Ÿฝ (0x1f3fd) [u1F3FD] 'Segoe UI Emoji'in seguiemj.ttf
๐Ÿฝ (0x1f3fd) [u1F3FD] 'Segoe UI Symbol'in seguisym.ttf

Solution 2:

You can use pywin32 to check for the required fonts.

import win32gui

deffontFamProc(font, tm, fonttype, names):
    names.append(font.lfFaceName)
    returnTrue

fonts = []

deviceContext  = win32gui.GetDC(None)
win32gui.EnumFontFamilies(deviceContext, None, fontFamProc, fonts)
win32gui.ReleaseDC(deviceContext, None)

print(fonts)

Solution 3:

Well, you could simply print all of Unicode and find out that way. E.g., (I can print most all if not all :

import io

with io.open("all_utf-8.txt", "w", encoding="utf8") as f:
    for n inrange(150000):  
        try:
            i = chr(n)
            if i.isprintable():
                print(f"{i}", end="", file=f)
            if n % 200 == 0:
                print(file=f)
        except UnicodeError:
            pass

(note the use of the built-in Python str method isprintable())

all unicode print & here's a bit of a zoom in so you can actually see the individual chars/glyphs... ๐Ÿ™‚ enter image description here

Post a Comment for "How To Determine If A Glyph Can Be Displayed?"