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)
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"
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])
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"]
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
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
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, )
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
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)
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])
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
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])