1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
"""
==========
Font table
==========
Matplotlib's font support is provided by the FreeType library.
Here, we use `~.Axes.table` to draw a table that shows the glyphs by Unicode
codepoint. For brevity, the table only contains the first 256 glyphs.
The example is a full working script. You can download it and use it to
investigate a font by running ::
python font_table.py /path/to/font/file
"""
import os
from pathlib import Path
import unicodedata
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
from matplotlib.ft2font import FT2Font
def print_glyphs(path):
"""
Print the all glyphs in the given font file to stdout.
Parameters
----------
path : str or None
The path to the font file. If None, use Matplotlib's default font.
"""
if path is None:
path = fm.findfont(fm.FontProperties()) # The default font.
font = FT2Font(path)
charmap = font.get_charmap()
max_indices_len = len(str(max(charmap.values())))
print("The font face contains the following glyphs:")
for char_code, glyph_index in charmap.items():
char = chr(char_code)
name = unicodedata.name(
char,
f"{char_code:#x} ({font.get_glyph_name(glyph_index)})")
print(f"{glyph_index:>{max_indices_len}} {char} {name}")
def draw_font_table(path):
"""
Draw a font table of the first 255 chars of the given font.
Parameters
----------
path : str or None
The path to the font file. If None, use Matplotlib's default font.
"""
if path is None:
path = fm.findfont(fm.FontProperties()) # The default font.
font = FT2Font(path)
# A charmap is a mapping of "character codes" (in the sense of a character
# encoding, e.g. latin-1) to glyph indices (i.e. the internal storage table
# of the font face).
# In FreeType>=2.1, a Unicode charmap (i.e. mapping Unicode codepoints)
# is selected by default. Moreover, recent versions of FreeType will
# automatically synthesize such a charmap if the font does not include one
# (this behavior depends on the font format; for example it is present
# since FreeType 2.0 for Type 1 fonts but only since FreeType 2.8 for
# TrueType (actually, SFNT) fonts).
# The code below (specifically, the ``chr(char_code)`` call) assumes that
# we have indeed selected a Unicode charmap.
codes = font.get_charmap().items()
labelc = [f"{i:X}" for i in range(16)]
labelr = [f"{i:02X}" for i in range(0, 16*16, 16)]
chars = [["" for c in range(16)] for r in range(16)]
for char_code, glyph_index in codes:
if char_code >= 256:
continue
row, col = divmod(char_code, 16)
chars[row][col] = chr(char_code)
fig, ax = plt.subplots(figsize=(8, 4))
ax.set_title(os.path.basename(path))
ax.set_axis_off()
table = ax.table(
cellText=chars,
rowLabels=labelr,
colLabels=labelc,
rowColours=["palegreen"] * 16,
colColours=["palegreen"] * 16,
cellColours=[[".95" for c in range(16)] for r in range(16)],
cellLoc='center',
loc='upper left',
)
for key, cell in table.get_celld().items():
row, col = key
if row > 0 and col > -1: # Beware of table's idiosyncratic indexing...
cell.set_text_props(font=Path(path))
fig.tight_layout()
plt.show()
if __name__ == "__main__":
from argparse import ArgumentParser
parser = ArgumentParser(description="Display a font table.")
parser.add_argument("path", nargs="?", help="Path to the font file.")
parser.add_argument("--print-all", action="store_true",
help="Additionally, print all chars to stdout.")
args = parser.parse_args()
if args.print_all:
print_glyphs(args.path)
draw_font_table(args.path)
|