Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
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,
    )
Ejemplo n.º 7
0
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)