def update_nametable(ttfont): """ - Add nameID 25 - Update fvar instance names and add fvar instance postscript names """ is_italic = font_is_italic(ttfont) has_mac_names = font_has_mac_names(ttfont) # Add nameID 25 # https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids vf_ps_name = _add_nameid_25(ttfont, is_italic, has_mac_names) # Update fvar instances instances = ttfont["fvar"].instances for inst in instances: wght_val = inst.coordinates["wght"] if wght_val not in WGHT: raise ValueError(f"Unsupported wght coord '{wght_val}'. Coord " "needs to be in {WGHT.keys()}") # Update instance subfamilyNameID wght_name = WGHT[wght_val] inst_name = wght_name if is_italic: inst_name = f"{inst_name} Italic" inst_name = inst_name.replace("Regular Italic", "Italic") ttfont['name'].setName(inst_name, inst.subfamilyNameID, 3, 1, 0x409) if has_mac_names: ttfont['name'].setName(inst_name, inst.subfamilyNameID, 1, 0, 0) # Add instance psName ps_name = f"{vf_ps_name}-{wght_name}" ps_name_id = ttfont['name'].addName(ps_name) inst.postscriptNameID = ps_name_id
def gen_stat(self, varfonts): if "axisOrder" not in self.config: self.config["axisOrder"] = [ ax.axisTag for ax in varfonts[0]["fvar"].axes ] if len(varfonts) > 1 and "ital" not in self.config["axisOrder"]: # *Are* any italic? Presumably, but test if any(font_is_italic(f) for f in varfonts): self.config["axisOrder"].append("ital") locations = self.config.get("statFormat4", None) if locations and 'stat' not in self.config: raise ValueError( "Cannot add statFormat 4 axisValues since no stat table has been declared." ) if "stylespaceFile" in self.config and self.config["stylespaceFile"]: self.gen_stat_stylespace(self.config["stylespaceFile"], varfonts) elif "stat" in self.config: gen_stat_tables_from_config(self.config["stat"], varfonts, locations=locations) else: gen_stat_tables(varfonts, self.config["axisOrder"]) for ttFont in varfonts: ttFont.save(ttFont.reader.file.name)
def css_font_faces(ttFonts, server_dir=None, position=None): """Generate @font-face CSSElements for a collection of fonts Args: ttFonts: a list containing ttFont instances server_dir: optional. A path to the root directory of the server. @font-face src urls are relative to the server's root dir. position: optional. Adds a suffix to the font-family name Returns: A list of @font-face CSSElements """ results = [] for ttFont in ttFonts: family_name = font_familyname(ttFont) style_name = font_stylename(ttFont) font_path = ttFont.reader.file.name path = (font_path if not server_dir else os.path.relpath( font_path, start=server_dir)) src = f"url({path})" font_family = _class_name(family_name, style_name, position) font_style = "italic" if font_is_italic(ttFont) else "normal" font_weight = css_font_weight(ttFont) font_stretch = WIDTH_CLASS_TO_CSS[ttFont["OS/2"].usWidthClass] if "fvar" in ttFont: fvar = ttFont["fvar"] axes = {a.axisTag: a for a in fvar.axes} if "wght" in axes: min_weight = int(axes["wght"].minValue) max_weight = int(axes["wght"].maxValue) font_weight = f"{min_weight} {max_weight}" if "wdth" in axes: min_width = int(axes["wdth"].minValue) max_width = int(axes["wdth"].maxValue) font_stretch = f"{min_width}% {max_width}%" if "ital" in axes: pass if "slnt" in axes: min_angle = int(axes["slnt"].minValue) max_angle = int(axes["slnt"].maxValue) font_style = f"oblique {min_angle}deg {max_angle}deg" font_face = CSSElement( "@font-face", src=src, font_family=font_family, font_weight=font_weight, font_stretch=font_stretch, font_style=font_style, ) results.append(font_face) return results
def gen_stat(self, varfonts): if len(varfonts) > 1 and "ital" not in self.config["axisOrder"]: # *Are* any italic? Presumably, but test if any(font_is_italic(f) for f in varfonts): self.config["axisOrder"].append("ital") if "stylespaceFile" in self.config and self.config["stylespaceFile"]: self.gen_stat_stylespace(self.config["stylespaceFile"], varfonts) elif "stat" in self.config: gen_stat_tables_from_config(self.config["stat"], varfonts) else: gen_stat_tables(varfonts, self.config["axisOrder"]) for ttFont in varfonts: ttFont.save(ttFont.reader.file.name)
def gen_stat_stylespace(self, stylespaceFile, varfonts): import warnings warnings.warn( ".stylespace files are supported for compatibility but" "you are encouraged to specify your STAT table axes in the config file" ) stylespace = statmake.classes.Stylespace.from_file(stylespaceFile) for ttFont in varfonts: if "ital" in self.config["axisOrder"]: if font_is_italic(ttFont): additional_locations = {"Italic": 1} else: additional_locations = {"Italic": 0} else: additional_locations = {} statmake.lib.apply_stylespace_to_variable_font( stylespace, ttFont, additional_locations)
def css_font_class_from_static(ttFont, position=None): family_name = font_familyname(ttFont) style_name = font_stylename(ttFont) class_name = _class_name(family_name, style_name, position) font_family = class_name font_weight = css_font_weight(ttFont) font_style = "italic" if font_is_italic(ttFont) else "normal" font_stretch = WIDTH_CLASS_TO_CSS[ttFont["OS/2"].usWidthClass] return CSSElement( class_name, _full_name=f"{family_name} {style_name}", _style=style_name, _font_path=ttFont.reader.file.name, font_family=font_family, font_weight=font_weight, font_style=font_style, font_stretch=font_stretch, )
def gen_stat_tables_from_config(stat, varfonts, has_italic=None): """ Generate a stat table for each font in a family from a Python configuration. Args: stat: either a dictionary or list as described below varfonts: a list of variable TTFont instances has_italic: a boolean indicating whether the family contains an italic. If not provided, the stylename of the font files are inspected to determine if any of them contain the word ``Italic``. The ``stat`` parameter should normally be a list of axis dictionaries in the format used by ``buildStatTable``. This list should *not* contain an entry for the ``ital`` axis, as this entry will be generated as appropriate for each font if ``has_italic`` is True. For example:: varfonts = [ "Source-Regular-VF[wdth].ttf", "Source-Italic-VF[wdth].ttf" ] stat = [ { "tag":"wdth", "name": "Width", "values": [ ... ] } ] Alternately, to allow different STAT table entries for each font, the ``stat`` parameter may be a dictionary, whose keys are source IDs (usually source filenames) corresponding to the appropriate entry in the ``varfonts`` dictionary and whose values are the list of axis dictionaries for the font. Note that in this case, the axes list is passed to ``buildStatTable`` with no further manipulation, meaning that if you want an ``ital`` axis, you should specify it manually as part of the dictionary. For example:: stat = { "Font[wght].ttf": [ { "tag":"wdth", "name": "Width", "values": [ ... ] }, { "tag":"ital", "name": "Italic", "values": [ ... ] } ], "Font-Italic[wght].ttf": [ { "tag":"wdth", "name": "Width", "values": [ ... ] }, { "tag":"ital", "name": "Italic", "values": [ ... ] } ] } """ assert all("fvar" in f for f in varfonts) # Check we have no italic if isinstance(stat, list): if has_italic is None: has_italic = any(font_is_italic(f) for f in varfonts) if has_italic: for ax in stat: if ax["name"] == "ital": raise ValueError("ital axis should not appear in stat config") ital_stat_for_roman = { "name": "Italic", "tag": "ital", "values": [dict(value=0, name="Roman", flags=0x2, linkedValue=1)] } ital_stat_for_italic = { "name": "Italic", "tag": "ital", "values": [dict(value=1, name="Italic")] } stat.append({}) # We will switch this entry between Roman and Italic for ttFont in varfonts: filename = os.path.basename(ttFont.reader.file.name) if isinstance(stat, dict): if filename not in stat: raise ValueError("Filename %s not found in stat dictionary" % filename) this_stat = stat[filename] else: if has_italic: if font_is_italic(ttFont): stat[-1] = ital_stat_for_italic else: stat[-1] = ital_stat_for_roman this_stat = stat buildStatTable(ttFont, this_stat)