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()
)
& here's a bit of a zoom in so you can actually see the individual chars/glyphs... ๐
Post a Comment for "How To Determine If A Glyph Can Be Displayed?"