Ejemplo n.º 1
0
    def _valid_designspace(self, designspace, ufo_module):
        """Make sure that the user-provided designspace has loaded fonts and
        that names are the same as those from the UFOs.
        """
        # TODO: (jany) really make a copy to avoid modifying the original object
        copy = designspace
        # Load only full UFO masters, sparse or "brace" layer sources are assumed
        # to point to existing layers within one of the full masters.
        for source in (s for s in copy.sources if not s.layerName):
            if not hasattr(source, "font") or source.font is None:
                if source.path:
                    # FIXME: (jany) consider not changing the caller's objects
                    source.font = util.open_ufo(source.path, ufo_module.Font)
                else:
                    dirname = os.path.dirname(designspace.path)
                    ufo_path = os.path.join(dirname, source.filename)
                    source.font = util.open_ufo(ufo_path, ufo_module.Font)
            if source.location is None:
                source.location = {}
            for name in ("familyName", "styleName"):
                if getattr(source, name) != getattr(source.font.info, name):
                    self.logger.warning(
                        dedent(
                            """\
                    The {name} is different between the UFO and the designspace source:
                        source filename: {filename}
                        source {name}: {source_name}
                        ufo {name}: {ufo_name}

                    The UFO name will be used.
                    """
                        ).format(
                            name=name,
                            filename=source.filename,
                            source_name=getattr(source, name),
                            ufo_name=getattr(source.font.info, name),
                        )
                    )
                    setattr(source, name, getattr(source.font.info, name))
        # An axis without a mapping will see its range information (min and max
        # values) lost when converted to a Glyps.app file. To combat this we
        # add an explicit identity mapping.
        for axis in copy.axes:
            if axis.map:
                continue
            if axis.minimum == axis.maximum:
                axis.map = [(axis.minimum, axis.minimum)]
            else:
                axis.map = [
                    (axis.minimum, axis.minimum),
                    (axis.maximum, axis.maximum),
                ]
        return copy
Ejemplo n.º 2
0
def ufo2glyphs(options):
    """Convert one designspace file or one or more UFOs to a Glyphs.app source file."""
    import fontTools.designspaceLib
    from glyphsLib.util import open_ufo

    ufo_module = __import__(options.ufo_module)

    sources = options.designspace_file_or_UFOs
    designspace_file = None
    if (len(sources) == 1 and sources[0].endswith(".designspace")
            and os.path.isfile(sources[0])):
        designspace_file = sources[0]
        designspace = fontTools.designspaceLib.DesignSpaceDocument()
        designspace.read(designspace_file)
        object_to_read = designspace
    elif all(
            source.endswith(".ufo") and os.path.isdir(source)
            for source in sources):
        ufos = [open_ufo(source, ufo_module.Font) for source in sources]
        ufos.sort(key=lambda ufo: [  # Order the masters by weight and width
            ufo.info.openTypeOS2WeightClass or 400,
            ufo.info.openTypeOS2WidthClass or 5,
        ])
        object_to_read = ufos
    else:
        print(
            "Please specify just one designspace file *or* one or more "
            "UFOs. They must end in '.designspace' or '.ufo', respectively.",
            file=sys.stderr,
        )
        return 1

    font = glyphsLib.to_glyphs(
        object_to_read,
        ufo_module=ufo_module,
        minimize_ufo_diffs=options.no_preserve_glyphsapp_metadata,
    )

    # Make the Glyphs file more suitable for roundtrip:
    font.customParameters["Disable Last Change"] = options.enable_last_change
    font.disablesAutomaticAlignment = options.enable_automatic_alignment

    if options.output_path:
        font.save(options.output_path)
    else:
        if designspace_file:
            filename_to_write = os.path.splitext(
                designspace_file)[0] + ".glyphs"
        else:
            filename_to_write = os.path.join(
                os.path.dirname(sources[0]),
                font.familyName.replace(" ", "") + ".glyphs",
            )
        font.save(filename_to_write)
Ejemplo n.º 3
0
def normalize_ufo_lib(path, ufo_module):
    """Go through each `lib` element recursively and transform `bools` into
    `int` because that's what's going to happen on round-trip with Glyphs.
    """
    font = util.open_ufo(path, ufo_module.Font)
    deboolize(font.lib)
    for layer in font.layers:
        deboolize(layer.lib)
        for glyph in layer:
            deboolize(glyph.lib)
    _save_overwrite_ufo(font, path)
Ejemplo n.º 4
0
    def _valid_designspace(self, designspace, ufo_module):
        """Make sure that the user-provided designspace has loaded fonts and
        that names are the same as those from the UFOs.
        """
        # TODO: (jany) really make a copy to avoid modifying the original object
        copy = designspace
        # Load only full UFO masters, sparse or "brace" layer sources are assumed
        # to point to existing layers within one of the full masters.
        for source in (s for s in copy.sources if not s.layerName):
            if not hasattr(source, "font") or source.font is None:
                if source.path:
                    # FIXME: (jany) consider not changing the caller's objects
                    source.font = util.open_ufo(source.path, ufo_module.Font)
                else:
                    dirname = os.path.dirname(designspace.path)
                    ufo_path = os.path.join(dirname, source.filename)
                    source.font = util.open_ufo(ufo_path, ufo_module.Font)
            if source.location is None:
                source.location = {}
            for name in ("familyName", "styleName"):
                if getattr(source, name) != getattr(source.font.info, name):
                    self.logger.warning(
                        dedent(
                            """\
                    The {name} is different between the UFO and the designspace source:
                        source filename: {filename}
                        source {name}: {source_name}
                        ufo {name}: {ufo_name}

                    The UFO name will be used.
                    """
                        ).format(
                            name=name,
                            filename=source.filename,
                            source_name=getattr(source, name),
                            ufo_name=getattr(source.font.info, name),
                        )
                    )
                    setattr(source, name, getattr(source.font.info, name))
        return copy
Ejemplo n.º 5
0
def test_designspace_generation_on_disk(datadir, tmpdir, ufo_module):
    glyphsLib.build_masters(str(datadir.join("BraceTestFont.glyphs")), str(tmpdir))

    ufo_paths = list(tmpdir.visit(fil="*.ufo"))
    assert len(ufo_paths) == 4  # Source layers should not be written to disk.
    for ufo_path in ufo_paths:
        ufo = open_ufo(ufo_path, ufo_module.Font)

        # Check that all glyphs have contours (brace layers are in "b" only, writing
        # the brace layer to disk would result in empty other glyphs).
        for layer in ufo.layers:
            for glyph in layer:
                if glyph.name == "space":
                    assert not glyph
                else:
                    assert glyph