def _load_font(data, codelist_map): if len(data) < 4: data = data + tuple([None] * (4 - len(data))) key, fname, name, codelistfile = data if not fname: if not name: raise Exception('must have name if no font provided') if not codelistfile: raise Exception('must have codelist file if no font provided') fontpath = None else: fontpath = path.join(data_dir, fname) if not path.isfile(fontpath): raise Exception('font "%s" not found' % fontpath) if codelistfile: codelist = _load_codelist(codelistfile, data_dir, codelist_map) if fname and (not codelistfile or not name): font = ttLib.TTFont(fontpath) if not name: names = font_data.get_name_records(font) name = names[16] if 16 in names else names[1] if 1 in names else None if not name: raise Exception('cannot read name from font "%s"' % fontpath) if not codelistfile: codelist = CodeList.fromset(font_data.get_cmap(font)) return key, fontpath, name, codelist
def get_glyph_name_from_gsub(char_seq, font): """Find the glyph name for ligature of a given character sequence from GSUB. """ cmap = font_data.get_cmap(font) # FIXME: So many assumptions are made here. try: first_glyph = cmap[char_seq[0]] rest_of_glyphs = [cmap[ch] for ch in char_seq[1:]] except KeyError: return None for lookup in font['GSUB'].table.LookupList.Lookup: ### This line is added for emoji_builder ### try: ### Thes following lines are indented for emoji_builder ### ligatures = lookup.SubTable[0].ligatures try: for ligature in ligatures[first_glyph]: if ligature.Component == rest_of_glyphs: return ligature.LigGlyph except KeyError: continue ### This line is added for emoji_builder ### except AttributeError: # If there are no ligatures at all, it's fine as well. ### This line is added for emoji_builder ### pass return None
def create_lookup(table, font, flag=0): """Create a Lookup based on mapping table.""" cmap = font_data.get_cmap(font) ligatures = {} for output, (ch1, ch2) in table.iteritems(): output = cmap[output] ch1 = get_glyph_name_or_create(ch1, font) ch2 = get_glyph_name_or_create(ch2, font) ligature = otTables.Ligature() ligature.CompCount = 2 ligature.Component = [ch2] ligature.LigGlyph = output try: ligatures[ch1].append(ligature) except KeyError: ligatures[ch1] = [ligature] ligature_subst = otTables.LigatureSubst() ligature_subst.ligatures = ligatures lookup = otTables.Lookup() lookup.LookupType = 4 lookup.LookupFlag = flag lookup.SubTableCount = 1 lookup.SubTable = [ligature_subst] return lookup
def subset_font_cmap(srcname, dstname, exclude=None, include=None, bump_version=True): opt = _DEFAULT_OPTIONS font = subset.load_font(srcname, opt) target_charset = set(font_data.get_cmap(font).keys()) if include is not None: target_charset &= include if exclude is not None: target_charset -= exclude subsetter = subset.Subsetter(options=opt) subsetter.populate(unicodes=target_charset) subsetter.subset(font) if bump_version: # assume version string has 'uh' if unhinted, else hinted. revision, version_string = swat_license.get_bumped_version(font) font['head'].fontRevision = revision font_data.set_name_record(font, _VERSION_ID, version_string) subset.save_font(font, dstname, opt)
def add_pua_cmap(source_file, target_file): """Add PUA characters to the cmap of the first font and save as second.""" font = ttLib.TTFont(source_file) cmap = font_data.get_cmap(font) for pua, (ch1, ch2) in (add_emoji_gsub.EMOJI_KEYCAPS.items() + add_emoji_gsub.EMOJI_FLAGS.items()): if pua not in cmap: glyph_name = get_glyph_name_from_gsub([ch1, ch2], font) if glyph_name is not None: cmap[pua] = glyph_name font.save(target_file)
def modify_font(font_name, font, presentation, emoji_variants): cmap_table = font_data.get_cmap(font) emoji = set(cmap_table.keys()) & emoji_variants if not emoji: print 'no emoji match those in %s' % font_name return uvs = VS_EMOJI if presentation == 'emoji' else VS_TEXT cmap14 = _c_m_a_p.CmapSubtable.newSubtable(14) cmap14.cmap = {} cmap14.uvsDict = {uvs: [[c, None] for c in sorted(emoji)]} cmap14.platformID = 0 cmap14.platEncID = 5 cmap14.language = 0xFF # what fontTools would have used font['cmap'].tables.append(cmap14)
def modify_font(font_name, font, presentation, emoji_variants): cmap_table = font_data.get_cmap(font) emoji = set(cmap_table.keys()) & emoji_variants if not emoji: print('no emoji match those in %s' % font_name) return uvs = VS_EMOJI if presentation == 'emoji' else VS_TEXT cmap14 = _c_m_a_p.CmapSubtable.newSubtable(14) cmap14.cmap = {} cmap14.uvsDict = {uvs: [[c, None] for c in sorted(emoji)]} cmap14.platformID = 0 cmap14.platEncID = 5 cmap14.language = 0xFF # what fontTools would have used font['cmap'].tables.append(cmap14)
def _get_cp_metrics(font, cp): # returns metrics for nominal glyph for cp, or None if cp not in font cmap = font_data.get_cmap(font) if cp not in cmap: return None glyphs = font.getGlyphSet() g = glyphs[cmap[cp]] pen = BoundsPen(glyphs) g.draw(pen) if not pen.bounds: return None xmin, ymin, xmax, ymax = pen.bounds return GMetrics( xmin, g.width - xmax, xmax - xmin, g.width, (ymin + ymax) / 2)
def create_glyph_data(font, collection): glyphorder = font.getGlyphOrder() data = [None] * len(glyphorder) name_to_index = {g: i for i, g in enumerate(glyphorder)} cmap = font_data.get_cmap(font) # if different cps map to the same glyph, this uses the last one index_to_cp = {name_to_index[cmap[cp]]: cp for cp in cmap} for i, g in enumerate(glyphorder): cp = index_to_cp.get(i, -1) name = "" if (i == 0 or cp >= 0 or g == "glyph%05d" % i) else g adv = collection.image_dict[i].adv.int data[i] = (adv, cp, name) return data
def get_glyph_name_or_create(char, font): """Return the glyph name for a character, creating if it doesn't exist.""" cmap = font_data.get_cmap(font) if char in cmap: return cmap[char] glyph_name = agl.UV2AGL[char] assert glyph_name not in font.glyphOrder font['hmtx'].metrics[glyph_name] = [0, 0] cmap[char] = glyph_name if 'glyf' in font: from fontTools.ttLib.tables import _g_l_y_f empty_glyph = _g_l_y_f.Glyph() font['glyf'].glyphs[glyph_name] = empty_glyph font.glyphOrder.append(glyph_name) return glyph_name
def get_glyph_name_from_gsub(char_seq, font): """Find the glyph name for ligature of a given character sequence from GSUB. """ cmap = font_data.get_cmap(font) # FIXME: So many assumptions are made here. try: first_glyph = cmap[char_seq[0]] rest_of_glyphs = [cmap[ch] for ch in char_seq[1:]] except KeyError: return None for lookup in font['GSUB'].table.LookupList.Lookup: ligatures = lookup.SubTable[0].ligatures try: for ligature in ligatures[first_glyph]: if ligature.Component == rest_of_glyphs: return ligature.LigGlyph except KeyError: continue return None
def merge_chars_from_bank(orig_font, bank_font, target_font, chars): """Merge glyphs from a bank font to another font. Only the glyphs themselves, the horizontal metrics, and the cmaps will be copied. """ bank_font = ttLib.TTFont(bank_font) orig_font = ttLib.TTFont(orig_font) bank_cmap = font_data.get_cmap(bank_font) extra_cmap = {} for char in sorted(chars): assert char in bank_cmap bank_glyph_name = bank_cmap[char] assert bank_glyph_name not in orig_font["glyf"].glyphs orig_font["glyf"][bank_glyph_name] = bank_font["glyf"][bank_glyph_name] orig_font["hmtx"][bank_glyph_name] = bank_font["hmtx"][bank_glyph_name] extra_cmap[char] = bank_glyph_name font_data.add_to_cmap(orig_font, extra_cmap) orig_font.save(target_font)
def merge_chars_from_bank(orig_font, bank_font, target_font, chars): """Merge glyphs from a bank font to another font. Only the glyphs themselves, the horizontal metrics, and the cmaps will be copied. """ bank_font = ttLib.TTFont(bank_font) orig_font = ttLib.TTFont(orig_font) bank_cmap = font_data.get_cmap(bank_font) extra_cmap = {} for char in sorted(chars): assert char in bank_cmap bank_glyph_name = bank_cmap[char] assert bank_glyph_name not in orig_font['glyf'].glyphs orig_font['glyf'][bank_glyph_name] = bank_font['glyf'][bank_glyph_name] orig_font['hmtx'][bank_glyph_name] = bank_font['hmtx'][bank_glyph_name] extra_cmap[char] = bank_glyph_name font_data.add_to_cmap(orig_font, extra_cmap) orig_font.save(target_font)
def subset_font_cmap( srcname, dstname, exclude=None, include=None, bump_version=True): opt = _DEFAULT_OPTIONS font = subset.load_font(srcname, opt) target_charset = set(font_data.get_cmap(font).keys()) if include is not None: target_charset &= include if exclude is not None: target_charset -= exclude subsetter = subset.Subsetter(options=opt) subsetter.populate(unicodes=target_charset) subsetter.subset(font) if bump_version: # assume version string has 'uh' if unhinted, else hinted. revision, version_string = swat_license.get_bumped_version(font) font['head'].fontRevision = revision font_data.set_name_record(font, _VERSION_ID, version_string) subset.save_font(font, dstname, opt)
def _get_cp_to_glyphix(font): # so, i should use glyph names, then the cmap is exactly what I want, no? cmap = font_data.get_cmap(font) # cp to glyph name name_to_index = {g: i for i, g in enumerate(font.getGlyphOrder())} return {cp: name_to_index[cmap[cp]] for cp in cmap}
def create_font_data(font, collection): cps = len(font_data.get_cmap(font)) version = font_data.font_version(font) return GlyphImageFontData._make(collection.file_header + (cps, version))
def fromfontcmap(fontname): font = ttLib.TTFont(fontname) return CodeList.fromset(font_data.get_cmap(font))