Example #1
0
def main():
    parser = argparse.ArgumentParser(
        prog="sfd2ufo", description="Convert FontForge fonts to UFO.")
    parser.add_argument("sfdfile",
                        metavar="FILE",
                        help="input font to process")
    parser.add_argument("ufofile", metavar="FILE", help="output font to write")
    parser.add_argument(
        "--ufo-anchors",
        action="store_true",
        help="output UFO anchors instead of writing them to feature file",
    )
    parser.add_argument(
        "--ufo-kerning",
        action="store_true",
        help="output UFO kerning instead of writing it to feature file",
    )
    parser.add_argument("--minimal",
                        action="store_true",
                        help="output enough UFO to build the font")

    args = parser.parse_args()

    font = Font()
    parser = SFDParser(
        args.sfdfile,
        font,
        args.ufo_anchors,
        args.ufo_kerning,
        args.minimal,
    )
    parser.parse()

    font.save(args.ufofile, overwrite=True, validate=False)
Example #2
0
def test_dataset(tmp_path: Path) -> None:
    font = Font()
    font.data["test.png"] = b"123"
    font.data["directory/test2.png"] = b"456"
    font_path = tmp_path / "a.ufo"
    font.save(font_path)

    font = Font.open(font_path)
    assert font.data["test.png"] == b"123"
    assert font.data["directory/test2.png"] == b"456"
Example #3
0
def step_merge_glyphs_from_ufo(path: Path, instance: ufoLib2.Font,
                               *args) -> None:
    textfile = ""
    for ar in args:
        textfile = ar

    ufo = ufoLib2.Font.open(path)
    if textfile:
        glyphSet = Path(textfile).read_text().split(" ")
        for glyph in glyphSet:
            instance.addGlyph(ufo[glyph])
    else:
        for glyph in ufo:
            if glyph.name not in instance:
                instance.addGlyph(ufo[glyph.name])
Example #4
0
def test_imageset(tmp_path: Path) -> None:
    font = Font()
    font.images["test.png"] = b"\x89PNG\r\n\x1a\n123"
    font.images["test2.png"] = b"\x89PNG\r\n\x1a\n456"
    font_path = tmp_path / "a.ufo"
    font.save(font_path)

    font = Font.open(font_path)
    assert font.images["test.png"] == b"\x89PNG\r\n\x1a\n123"
    assert font.images["test2.png"] == b"\x89PNG\r\n\x1a\n456"

    with pytest.raises(ValueError, match=r".*subdirectories.*"):
        font.images["directory/test2.png"] = b"\x89PNG\r\n\x1a\n456"
    with pytest.raises(KeyError):
        font.images["directory/test2.png"]
Example #5
0
def openFont(path):
    from ufoLib2 import Font

    font = Font(validate=False)
    parser = SFDParser(path,
                       font,
                       ignore_uvs=False,
                       ufo_anchors=False,
                       ufo_kerning=False,
                       minimal=True)
    parser.parse()

    return font
Example #6
0
    def _preprocess(self):
        ufo = UFOFont.open(self.source, validate=False)

        if self.ren is not None:
            with open(self.ren, "r") as f:
                logger.info(f"Setting {self.name} final glyph names")
                lines = f.read().split("\n")
                lines = [l.split() for l in lines if l and not l.startswith("%")]
                ufo.lib[PSNAMES_KEY] = {l[0]: l[1] for l in lines}

        if "fstype" in self.set:
            ufo.info.openTypeOS2Type = self.set["fstype"]

        otl = TTFont(self.ttf["source"]) if "source" in self.ttf else None

        return ufo, otl
Example #7
0
    def create(
        font_config: FontConfig,
        ufo: ufoLib2.Font,
        filename: str,
        glyph_id: int,
        glyph_name: str,
        codepoints: Tuple[int, ...],
        svg: SVG,
    ) -> "ColorGlyph":
        logging.debug(" ColorGlyph for %s (%s)", filename, codepoints)
        base_glyph = ufo.newGlyph(glyph_name)

        # non-square aspect ratio == proportional width; square == monospace
        view_box = svg.view_box()
        if view_box is not None:
            base_glyph.width = _color_glyph_advance_width(view_box, font_config)
        else:
            base_glyph.width = font_config.width

        # Setup direct access to the glyph if possible
        if len(codepoints) == 1:
            base_glyph.unicode = next(iter(codepoints))

        # Grab the transform + (color, glyph) layers unless they aren't to be touched
        # or cannot possibly paint
        painted_layers = ()
        if not font_config.transform.is_degenerate():
            if font_config.has_picosvgs:
                painted_layers = tuple(
                    _painted_layers(
                        filename,
                        font_config,
                        svg,
                        base_glyph.width,
                    )
                )

        return ColorGlyph(
            ufo,
            filename,
            glyph_name,
            glyph_id,
            codepoints,
            painted_layers,
            svg,
            font_config.transform,
        )
Example #8
0
def _glyf_ufo(config: FontConfig, ufo: ufoLib2.Font,
              color_glyphs: Tuple[ColorGlyph, ...]):
    # We want to mutate our view of color_glyphs
    color_glyphs = list(color_glyphs)

    # glyphs by reuse_key
    glyph_cache = GlyphReuseCache(config.reuse_tolerance)
    glyph_uses = Counter()
    for i, color_glyph in enumerate(color_glyphs):
        logging.debug(
            "%s %s %s",
            ufo.info.familyName,
            color_glyph.glyph_name,
            color_glyph.transform_for_font_space(),
        )
        parent_glyph = ufo[color_glyph.glyph_name]

        # generate glyphs for PaintGlyph's and assign glyph names
        color_glyphs[i] = color_glyph = _migrate_paths_to_ufo_glyphs(
            color_glyph, glyph_cache)

        for root in color_glyph.painted_layers:
            for context in root.breadth_first():
                # For 'glyf' just dump anything that isn't a PaintGlyph
                if not isinstance(context.paint, PaintGlyph):
                    continue
                paint_glyph = cast(PaintGlyph, context.paint)
                glyph = ufo.get(paint_glyph.glyph)
                parent_glyph.components.append(
                    Component(baseGlyph=glyph.name,
                              transformation=context.transform))
                glyph_uses[glyph.name] += 1

    # No great reason to keep single-component glyphs around (unless reused)
    for color_glyph in color_glyphs:
        parent_glyph = ufo[color_glyph.glyph_name]
        if (len(parent_glyph.components) == 1
                and glyph_uses[parent_glyph.components[0].baseGlyph] == 1):
            component = ufo[parent_glyph.components[0].baseGlyph]
            del ufo[component.name]
            component.unicode = parent_glyph.unicode
            ufo[color_glyph.glyph_name] = component
            assert component.name == color_glyph.glyph_name
Example #9
0
def main(args=None):
    parser = ArgumentParser(description="Pre-process UFO files")
    parser.add_argument("input")
    parser.add_argument("ren")
    parser.add_argument("otl")
    parser.add_argument("output")

    options = parser.parse_args(args)

    font = Font.open(options.input, validate=False)
    font.features.text = ""
    font.kerning = {}
    font.groups = {}

    font.lib[PSNAMES_KEY] = load_names(options.ren)
    otf = TTFont(options.otl, lazy=True)
    tables = {"GDEF", "GSUB", "GPOS"}
    if "MATH" in otf:
        tables |= {"MATH", "cmap"}
    add_otl(font, otf, tables)

    font.save(options.output, validate=False, overwrite=True)
Example #10
0
def step_merge_glyphs_from_ufo(path: Path, instance: ufoLib2.Font) -> None:
    ufo = ufoLib2.Font.open(path)
    for glyph in ufo.glyphOrder:
        if glyph not in instance.glyphOrder:
            instance.addGlyph(ufo[glyph])
Example #11
0
def swap_glyph_names(font: ufoLib2.Font, name_old: str, name_new: str):
    """Swap two existing glyphs in the default layer of a font (outlines,
    width, component references, kerning references, group membership).

    The idea behind swapping instead of overwriting is explained in
    https://github.com/fonttools/fonttools/tree/master/Doc/source/designspaceLib#ufo-instances.
    We need to keep the old glyph around in case any other glyph references
    it; glyphs that are not explicitly substituted by rules should not be
    affected by the rule application.

    The .unicodes are not swapped. The rules mechanism is supposed to swap
    glyphs, not characters.
    """

    if name_old not in font or name_new not in font:
        raise InstantiatorError(
            f"Cannot swap glyphs '{name_old}' and '{name_new}', as either or both are "
            "missing.")

    # 1. Swap outlines and glyph width. Ignore lib content and other properties.
    glyph_swap = ufoLib2.objects.Glyph(name="temporary_swap_glyph")
    glyph_old = font[name_old]
    glyph_new = font[name_new]

    p = glyph_swap.getPointPen()
    glyph_old.drawPoints(p)
    glyph_swap.width = glyph_old.width

    glyph_old.clear()
    p = glyph_old.getPointPen()
    glyph_new.drawPoints(p)
    glyph_old.width = glyph_new.width

    glyph_new.clear()
    p = glyph_new.getPointPen()
    glyph_swap.drawPoints(p)
    glyph_new.width = glyph_swap.width

    # 2. Remap components.
    for g in font:
        for c in g.components:
            if c.baseGlyph == name_old:
                c.baseGlyph = name_new
            elif c.baseGlyph == name_new:
                c.baseGlyph = name_old

    # 3. Swap literal names in kerning.
    kerning_new = {}
    for first, second in font.kerning.keys():
        value = font.kerning[(first, second)]
        if first == name_old:
            first = name_new
        elif first == name_new:
            first = name_old
        if second == name_old:
            second = name_new
        elif second == name_new:
            second = name_old
        kerning_new[(first, second)] = value
    font.kerning = kerning_new

    # 4. Swap names in groups.
    for group_name, group_members in font.groups.items():
        group_members_new = []
        for name in group_members:
            if name == name_old:
                group_members_new.append(name_new)
            elif name == name_new:
                group_members_new.append(name_old)
            else:
                group_members_new.append(name)
        font.groups[group_name] = group_members_new
Example #12
0
def step_merge_glyphs_from_ufo(path: Path, instance: ufoLib2.Font) -> None:
    ufo = ufoLib2.Font.open(path)
    for glyph in ufo:
        if glyph.name not in instance:
            instance.addGlyph(ufo[glyph.name])