generate_font.py (6011B)
1 #!/usr/bin/env python3 2 3 import string 4 import os 5 import sys 6 import json 7 import fontforge 8 import psMat 9 10 PUA_START = 0xE000 11 PUA_END = 0xF8FF 12 FONT_EM = 1024 13 POWERLINE_START = 0xE0A0 14 POWERLINE_END = 0xE0D5 15 16 def read_map_names(filename): 17 array = [] 18 with open(filename) as file_map: 19 lines = file_map.readlines() 20 lines = [x.strip() for x in lines] 21 for line in lines: 22 if len(line) == 0: 23 continue 24 tab = line.split() 25 if tab[0][0] == '@': 26 array.append((tab[0][1:], ord(tab[1][0]))) 27 else: 28 array.append((tab[0], int(tab[1], 16))) 29 return array 30 31 def lookup_map_name(map_names, codepoint, fallback_name): 32 for name, code in map_names: 33 if code == codepoint: 34 return name 35 return fallback_name 36 37 # Insert the powerline glyphs at the same place that all the patched powerline fonts to make 38 # our font compatible with most of plugins/modules that insert those glyphs 39 def insert_powerline_extra(dest): 40 codepoint = POWERLINE_START 41 font = fontforge.open("./fonts/PowerlineExtraSymbols.otf") 42 font.em = FONT_EM 43 map_names = read_map_names("./fonts/PowerlineExtraSymbols-map") 44 excludes = [ 0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7, 0xE0A8, 0xE0A9, 0xE0AA, 0xE0AB, 45 0xE0AC, 0xE0AD, 0xE0AE, 0xE0AF, 0xE0C9, 0xE0CB, 0xE0D3 ] 46 inserted = [] 47 48 while codepoint < POWERLINE_END: 49 if codepoint in excludes: 50 codepoint += 1 51 continue 52 font.selection.select(codepoint) 53 font.copy() 54 dest.selection.select(codepoint) 55 dest.paste() 56 inserted.append(codepoint) 57 codepoint += 1 58 print("#powerline-extras:" + str(len(inserted))) 59 for x in inserted: 60 number = hex(x).replace("0x", "") 61 name = lookup_map_name(map_names, x, number) 62 print("powerline_" + name + ":" + number, end=';') 63 print("") 64 65 # Return true if the format of the name is something like 'uniXXXX' where X are 66 # hexadecimals 67 def is_default_name(name): 68 if (len(name) != 7 or 69 not name.startswith("uni") or 70 not all(c in string.hexdigits for c in name[-4:])): 71 return False 72 return True 73 74 # Name the glyph according to the font name 75 def make_name(name, name_font): 76 name = name.lower() 77 if is_default_name(name): 78 return name_font + "_" + name[-4:] 79 return name_font + "_" + name.replace("-", "_") 80 81 if len(sys.argv) < 2: 82 print("Give me a config file", file=sys.stderr) 83 sys.exit(1) 84 85 with open(sys.argv[1]) as config_file: 86 config_data = json.load(config_file) 87 88 dest = fontforge.font() 89 dest.em = FONT_EM 90 # dest.encoding = "UnicodeFull" 91 dest.encoding = "ISO10646" 92 93 insert_powerline_extra(dest) 94 95 codepoint = PUA_START 96 97 for json_file in config_data: 98 99 font = fontforge.open(json_file["path"]) 100 font.em = FONT_EM 101 102 excludes = [] 103 if "excludes" in json_file: 104 excludes = list(map(lambda x : int(x, 16), json_file["excludes"])) 105 106 start_from = 0 107 if "start-from" in json_file: 108 start_from = int(json_file["start-from"], 16) 109 110 until = -1 111 if "until" in json_file: 112 until = int(json_file["until"], 16) 113 114 move_vertically = 0 115 if "move-vertically" in json_file: 116 move_vertically = int(json_file["move-vertically"]) 117 118 name_font = json_file["name"] 119 if "short-name" in json_file: 120 name_font = json_file["short-name"] 121 name_font = name_font.replace("-", "_") 122 123 map_names = [] 124 if "map-names" in json_file: 125 map_names = read_map_names(json_file["map-names"]) 126 127 start = codepoint 128 inserted = [] 129 130 for symbol in font.glyphs("encoding"): 131 if codepoint == POWERLINE_START: 132 codepoint = POWERLINE_END 133 if (symbol.encoding in excludes or 134 symbol.encoding < start_from or 135 (until > 0 and symbol.encoding >= until)): 136 continue 137 if symbol.width > 0 and symbol.unicode > 0: 138 encoding = symbol.encoding 139 name = symbol.glyphname 140 font.selection.select(encoding) 141 font.copy() 142 if encoding == 0x20: 143 dest.selection.select(0x20) 144 dest.paste() 145 continue 146 dest.selection.select(codepoint) 147 dest.paste() 148 dest.transform(psMat.translate(0, move_vertically)) 149 if len(map_names) > 0: 150 name = lookup_map_name(map_names, encoding, name) 151 new_name = make_name(name, name_font) 152 dest.createMappedChar(codepoint).glyphname = new_name 153 inserted.append((new_name ,codepoint)) 154 codepoint += 1 155 156 print("#" + json_file["name"] + ":" + str(len(inserted))) 157 for (name, x) in inserted: 158 print(name + ":" + str(hex(x)).replace("0x", ""), end=';') 159 print("") 160 161 ascent = dest.ascent 162 descent = dest.descent 163 164 dest.os2_winascent_add = 0 165 dest.os2_windescent_add = 0 166 dest.os2_typoascent_add = 0 167 dest.os2_typodescent_add = 0 168 dest.hhea_ascent_add = 0 169 dest.hhea_descent_add = 0 170 171 # print ("ASCENT: " + str(ascent)) 172 # print ("DESCENT: " + str(descent)) 173 174 dest.os2_winascent = ascent 175 dest.os2_windescent = descent 176 dest.os2_typoascent = ascent 177 dest.os2_typodescent = -descent 178 dest.hhea_ascent = ascent 179 dest.hhea_descent = -descent 180 181 dest.em = FONT_EM 182 dest.fontname = "icons-in-terminal" 183 dest.familyname = "icons-in-terminal" 184 dest.fullname = "icons-in-terminal" 185 dest.appendSFNTName('English (US)', 'Preferred Family', dest.familyname) 186 dest.appendSFNTName('English (US)', 'Compatible Full', dest.fullname) 187 dest.fontname= "icons-in-terminal" 188 dest.generate("icons-in-terminal.ttf") 189 sys.exit(0) 190 191 sys.exit(1)