Beispiel #1
0
 def test_insertGlyph(self):
     font = Font(getTestFontPath())
     glyph = Glyph()
     glyph.name = "NewGlyphTest"
     self.assertEqual(sorted(font.keys()), ["A", "B", "C"])
     font.insertGlyph(glyph)
     self.assertEqual(sorted(font.keys()), ["A", "B", "C", "NewGlyphTest"])
Beispiel #2
0
 def test_insertGlyph(self):
     font = Font(getTestFontPath())
     glyph = Glyph()
     glyph.name = "NewGlyphTest"
     self.assertEqual(sorted(font.keys()), ["A", "B", "C"])
     font.insertGlyph(glyph)
     self.assertEqual(sorted(font.keys()), ["A", "B", "C", "NewGlyphTest"])
Beispiel #3
0
def create_font(info_params, glyphs):
    font = Font()
    for info_key, info_value in info_params:
        setattr(font.info, info_key, info_value)
    for glyph in glyphs:
        font.insertGlyph(glyph)
    return font
Beispiel #4
0
 def test_glyph_dispatcher_inserted(self):
     font = Font()
     font.newGlyph("A")
     glyph = font["A"]
     pen = glyph.getPointPen()
     pen.beginPath()
     pen.addPoint((0, 0), segmentType="line")
     pen.addPoint((0, 100), segmentType="line")
     pen.addPoint((100, 100), segmentType="line")
     pen.addPoint((100, 0), segmentType="line")
     pen.endPath()
     contour = glyph[0]
     component = Component()
     glyph.appendComponent(component)
     anchor = Anchor()
     glyph.appendAnchor(anchor)
     guideline = Guideline()
     glyph.appendGuideline(guideline)
     sourceGlyph = glyph
     newFont = Font()
     insertedGlyph = newFont.insertGlyph(sourceGlyph)
     contour = insertedGlyph[0]
     self.assertTrue(contour.getParent(), insertedGlyph)
     self.assertTrue(contour.dispatcher, newFont.dispatcher)
     component = insertedGlyph.components[0]
     self.assertTrue(component.getParent(), insertedGlyph)
     self.assertTrue(component.dispatcher, newFont.dispatcher)
     anchor = insertedGlyph.anchors[0]
     self.assertTrue(anchor.getParent(), insertedGlyph)
     self.assertTrue(anchor.dispatcher, newFont.dispatcher)
     guideline = insertedGlyph.guidelines[0]
     self.assertTrue(guideline.getParent(), insertedGlyph)
     self.assertTrue(guideline.dispatcher, newFont.dispatcher)
def combineGlyphs(path1, path2, destPath):
    """
        Combines the glyphs of two UFOs and saves result to a new ufo.
        This only combines glyphs, so the first UFO path should be the one
        that you want all the metadata from.
    """
    
    ufo1 = Font(path1)
    ufo2 = Font(path2)
    added_glyphs = []
    for glyph in ufo2:
        if glyph.name not in ufo1:
            print "Inserting %s" % glyph.name
            ufo1.insertGlyph(glyph)
            added_glyphs.append(glyph.name)
    ufo1.save(destPath)
 def test_glyph_dispatcher_inserted(self):
     font = Font()
     font.newGlyph("A")
     glyph = font["A"]
     pen = glyph.getPointPen()
     pen.beginPath()
     pen.addPoint((0, 0), segmentType="line")
     pen.addPoint((0, 100), segmentType="line")
     pen.addPoint((100, 100), segmentType="line")
     pen.addPoint((100, 0), segmentType="line")
     pen.endPath()
     contour = glyph[0]
     component = Component()
     glyph.appendComponent(component)
     anchor = Anchor()
     glyph.appendAnchor(anchor)
     guideline = Guideline()
     glyph.appendGuideline(guideline)
     sourceGlyph = glyph
     newFont = Font()
     insertedGlyph = newFont.insertGlyph(sourceGlyph)
     contour = insertedGlyph[0]
     self.assertTrue(contour.getParent(), insertedGlyph)
     self.assertTrue(contour.dispatcher, newFont.dispatcher)
     component = insertedGlyph.components[0]
     self.assertTrue(component.getParent(), insertedGlyph)
     self.assertTrue(component.dispatcher, newFont.dispatcher)
     anchor = insertedGlyph.anchors[0]
     self.assertTrue(anchor.getParent(), insertedGlyph)
     self.assertTrue(anchor.dispatcher, newFont.dispatcher)
     guideline = insertedGlyph.guidelines[0]
     self.assertTrue(guideline.getParent(), insertedGlyph)
     self.assertTrue(guideline.dispatcher, newFont.dispatcher)
Beispiel #7
0
def combineGlyphs(path1, path2, destPath):
    """
        Combines the glyphs of two UFOs and saves result to a new ufo.
        This only combines glyphs, so the first UFO path should be the one
        that you want all the metadata from.
    """

    ufo1 = Font(path1)
    ufo2 = Font(path2)
    added_glyphs = []
    for glyph in ufo2:
        if glyph.name not in ufo1:
            print "Inserting %s" % glyph.name
            ufo1.insertGlyph(glyph)
            added_glyphs.append(glyph.name)
        else:
            print "Skipping %s" % glyph.name
    ufo1.save(destPath)
    print "Combined UFO saved at %s" % destPath
                                verbose=False)
print("Reading DesignSpace...")
doc.process(makeGlyphs=True, makeKerning=True, makeInfo=True)
os.remove(tmpDesignSpace)  # clean up

# update the instances with the source fonts
# print str(instances) + ' instances! '
for instance in instances:
    fileName = os.path.basename(instance["fileName"])
    source_path = os.path.join(src_dir, fileName)
    instance_path = os.path.join(instance_dir, fileName)
    source_font = Font(source_path)
    instance_font = Font(instance_path)
    # insert the source glyphs in the instance font
    for glyph in source_font:
        instance_font.insertGlyph(glyph)
    master_path = os.path.join(master_dir, fileName)
    instance_font.save(master_path)

designSpace = "sources/Amstelvar-NewSpaceNames/Italic/Amstelvar-Italic-010.designspace"
sources = [
    dict(path="master_ufo/Amstelvar-Italic.ufo",
         name="Amstelvar-Italic.ufo",
         location=dict(wght=400, wdth=100, opsz=14, GRAD=0),
         styleName="Regular",
         familyName=familyName,
         copyInfo=True),

    ##	Main
    dict(path="master_ufo/Amstelvar-Italic-GRAD-1.ufo",
         name="Amstelvar-Italic-GRAD-1.ufo",
Beispiel #9
0
def merge(args):
    arabic = Font(args.arabicfile)

    to_ufo_propagate_font_anchors(None, arabic)

    latin = Font(args.latinfile)

    addPlaceHolders(arabic)

    unicodes = []
    for glyph in arabic:
        unicodes.extend(glyph.unicodes)

    for name in latin.glyphOrder:
        if name in ("space", "nbspace", "CR", "NULL", ".notdef"):
            continue
        glyph = latin[name]
        assert glyph.name not in arabic, glyph.name
        assert glyph.unicodes not in unicodes, glyph.unicodes
        # Strip anchors from f_ ligatures, there are broken.
        # See https://github.com/googlei18n/glyphsLib/issues/313
        if name.startswith("f_"):
            glyph.anchors = {}
        arabic.insertGlyph(glyph)

    # Copy kerning and groups.
    arabic.groups.update(latin.groups)
    arabic.kerning.update(latin.kerning)

    for attr in ("xHeight", "capHeight"):
        value = getattr(latin.info, attr)
        if value is not None:
            setattr(arabic.info, attr, getattr(latin.info, attr))

    # Merge Arabic and Latin features, making sure languagesystem statements
    # come first.
    langsys = []
    statements = []
    for font in (arabic, latin):
        featurefile = UnicodeIO(tounicode(font.features.text))
        fea = parser.Parser(featurefile, []).parse()
        langsys += [
            s for s in fea.statements
            if isinstance(s, ast.LanguageSystemStatement)
        ]
        statements += [
            s for s in fea.statements
            if not isinstance(s, ast.LanguageSystemStatement)
        ]
    # Drop GDEF table, we want to generate one based on final features.
    statements = [s for s in statements if not isinstance(s, ast.TableBlock)]
    # Make sure DFLT is the first.
    langsys = sorted(langsys, key=attrgetter("script"))
    fea.statements = langsys + statements
    arabic.features.text = fea.asFea()

    glyphOrder = arabic.glyphOrder + latin.glyphOrder

    # Make sure we have a fixed glyph order by using the original Arabic and
    # Latin glyph order, not whatever we end up with after adding glyphs.
    arabic.glyphOrder = sorted(arabic.glyphOrder, key=glyphOrder.index)

    # Set metadata
    arabic.info.versionMajor, arabic.info.versionMinor = map(
        int, args.version.split("."))
    arabic.info.copyright = u"Copyright © 2015-%s The Reem Kufi Project Authors." % datetime.now(
    ).year

    return arabic
Beispiel #10
0
def merge(args):
    """Merges Arabic and Latin fonts together, and messages the combined font a
    bit. Returns the combined font."""

    ufo = Font(args.arabicfile)

    to_ufo_propagate_font_anchors(None, ufo)

    latin = Font(args.latinfile)

    ufo.lib[POSTSCRIPT_NAMES] = {}

    # Save original glyph order, used below.
    glyphOrder = ufo.glyphOrder + latin.glyphOrder

    # Generate production glyph names for Arabic glyphs, in case it differs
    # from working names. This will be used by ufo2ft to set the final glyph
    # names in the font file.
    for glyph in ufo:
        if glyph.unicode is not None:
            if glyph.unicode < 0xffff:
                postName = "uni%04X" % glyph.unicode
            else:
                postName = "u%06X" % glyph.unicode
            if postName != glyph.name:
                ufo.lib[POSTSCRIPT_NAMES][glyph.name] = postName

    # Merge Arabic and Latin features, making sure languagesystem statements
    # come first.
    features = ufo.features
    langsys = []
    statements = []
    for font in (ufo, latin):
        featurefile = os.path.join(font.path, "features.fea")
        fea = parser.Parser(featurefile, font.glyphOrder).parse()
        langsys += [
            s for s in fea.statements
            if isinstance(s, ast.LanguageSystemStatement)
        ]
        statements += [
            s for s in fea.statements
            if not isinstance(s, ast.LanguageSystemStatement)
        ]
        # We will regenerate kern, mark and mkmk features, and aalt is useless.
        statements = [
            s for s in statements
            if getattr(s, "name", None) not in ("aalt", "kern", "mark", "mkmk")
        ]
        # These will be regenerated as well
        statements = [
            s for s in statements if not isinstance(s, ast.MarkClassDefinition)
        ]
    # Drop tables in fea, we don’t want them.
    statements = [s for s in statements if not isinstance(s, ast.TableBlock)]
    # Make sure DFLT is the first.
    langsys = sorted(langsys, key=attrgetter("script"))
    fea.statements = langsys + statements
    features.text = fea.asFea()

    features.text += generateStyleSets(ufo)

    # Source Sans Pro has different advance widths for space and NBSP
    # glyphs, fix it.
    latin["nbspace"].width = latin["space"].width

    # Set Latin production names
    ufo.lib[POSTSCRIPT_NAMES].update(latin.lib[POSTSCRIPT_NAMES])

    # Copy Latin glyphs.
    for name in latin.glyphOrder:
        glyph = latin[name]
        # Remove anchors from spacing marks, otherwise ufo2ft will give them
        # mark glyph class which will cause HarfBuzz to zero their width.
        if glyph.unicode and unicodedata.category(unichr(
                glyph.unicode)) in ("Sk", "Lm"):
            for anchor in glyph.anchors:
                glyph.removeAnchor(anchor)
        # Add Arabic anchors to the dotted circle, we use an offset of 100
        # units because the Latin anchors are too close to the glyph.
        offset = 100
        if glyph.unicode == 0x25CC:
            for anchor in glyph.anchors:
                if anchor.name == "aboveLC":
                    glyph.appendAnchor(
                        dict(name="markAbove", x=anchor.x,
                             y=anchor.y + offset))
                    glyph.appendAnchor(
                        dict(name="hamzaAbove",
                             x=anchor.x,
                             y=anchor.y + offset))
                if anchor.name == "belowLC":
                    glyph.appendAnchor(
                        dict(name="markBelow", x=anchor.x,
                             y=anchor.y - offset))
                    glyph.appendAnchor(
                        dict(name="hamzaBelow",
                             x=anchor.x,
                             y=anchor.y - offset))
        # Break loudly if we have duplicated glyph in Latin and Arabic.
        # TODO should check duplicated Unicode values as well
        assert glyph.name not in ufo, glyph.name
        ufo.insertGlyph(glyph)

    # Copy kerning and groups.
    ufo.groups.update(latin.groups)
    ufo.kerning.update(latin.kerning)

    # We don’t set these in the Arabic font, so we just copy the Latin’s.
    for attr in ("xHeight", "capHeight"):
        value = getattr(latin.info, attr)
        if value is not None:
            setattr(ufo.info, attr, getattr(latin.info, attr))

    # Make sure we don’t have glyphs with the same unicode value
    unicodes = []
    for glyph in ufo:
        unicodes.extend(glyph.unicodes)
    duplicates = set([u for u in unicodes if unicodes.count(u) > 1])
    assert len(duplicates) == 0, "Duplicate unicodes: %s " % (
        ["%04X" % d for d in duplicates])

    # Make sure we have a fixed glyph order by using the original Arabic and
    # Latin glyph order, not whatever we end up with after adding glyphs.
    ufo.glyphOrder = sorted(ufo.glyphOrder, key=glyphOrder.index)

    return ufo
Beispiel #11
0
                scripts[script].append(lang)
    return OrderedDict((script, tuple(langs)) for script,langs in scripts.items())


if __name__ == '__main__':
    from defcon import Font

    font = Font(path=sys.argv[2])
    for mergePath in sys.argv[3:]:
        merge = Font(path=mergePath)
        # merge glyphs
        for name in merge.keys():
            glyph = merge[name]
            # had an error related to anchors, but I don't need anchors here
            glyph.anchors = []
            font.insertGlyph(glyph, name=name)
        # merge groups
        font.groups.update(merge.groups)
        # merge kerning
        font.kerning.update(merge.kerning)



    # scripts = {'arab': ('dflt', 'ARA ', 'URD ', 'FAR '), 'latn': ('dflt', 'TRK ')}
    # scripts = scriptsFromFea(sys.argv[1])
    # scripts = {'arab': ('dflt', ), 'latn': ('dflt', )}
    scripts = {
               'arab': ('dflt', 'ARA ', 'URD ', 'FAR ')
             , 'latn': ('dflt', 'AZE', 'CRT', 'KAZ', 'MOL', 'ROM', 'TAT', 'TRK' )
             }
Beispiel #12
0
def merge(args):
    """Merges Arabic and Latin fonts together, and messages the combined font a
    bit. Returns the combined font."""

    ufo = Font(args.arabicfile)

    propagate_font_anchors(ufo)

    latin = Font(args.latinfile)
    # Parse the GlyphOrderAndAliasDB file for Unicode values and production
    # glyph names of the Latin glyphs.
    goadb = GOADBParser(
        os.path.dirname(args.latinfile) + "/../GlyphOrderAndAliasDB")

    ufo.lib[POSTSCRIPT_NAMES] = {}

    # Save original glyph order, used below.
    glyphOrder = ufo.glyphOrder + latin.glyphOrder

    # Generate production glyph names for Arabic glyphs, in case it differs
    # from working names. This will be used by ufo2ft to set the final glyph
    # names in the font file.
    for glyph in ufo:
        if glyph.unicode is not None:
            if glyph.unicode < 0xffff:
                postName = "uni%04X" % glyph.unicode
            else:
                postName = "u%06X" % glyph.unicode
            if postName != glyph.name:
                ufo.lib[POSTSCRIPT_NAMES][glyph.name] = postName

    # Populate the font’s feature text, we keep our main feature file out of
    # the UFO to share it between the fonts.
    features = ufo.features
    with open(args.feature_file) as feafile:
        fea = feafile.read()
        # Set Latin language system, ufo2ft will use it when generating kern
        # feature.
        features.text += fea.replace("#{languagesystems}",
                                     "languagesystem latn dflt;")
    features.text += generateStyleSets(ufo)

    for glyph in latin:
        if glyph.name in goadb.encodings:
            glyph.unicode = goadb.encodings[glyph.name]

    # Source Sans Pro has different advance widths for space and NBSP
    # glyphs, fix it.
    latin["nbspace"].width = latin["space"].width

    glyphs, components = collectGlyphs(latin, args.latin_subset)

    counter = Counter(components)
    uniqueComponents = set()
    for name in counter:
        if name not in glyphs:
            latin[name].unicode = None
        if counter[name] == 1:
            uniqueComponents.add(name)
        else:
            glyphs.add(name)

    # Set Latin production names
    ufo.lib[POSTSCRIPT_NAMES].update(goadb.names)

    # Copy Latin glyphs.
    for name in glyphs:
        glyph = latin[name]
        for component in glyph.components:
            if component.baseGlyph in uniqueComponents:
                glyph.decomposeComponent(component)
        # Remove anchors from spacing marks, otherwise ufo2ft will give them
        # mark glyph class which will cause HarfBuzz to zero their width.
        if glyph.unicode and unicodedata.category(unichr(
                glyph.unicode)) in ("Sk", "Lm"):
            for anchor in glyph.anchors:
                glyph.removeAnchor(anchor)
        # Add Arabic anchors to the dotted circle, we use an offset of 100
        # units because the Latin anchors are too close to the glyph.
        offset = 100
        if glyph.unicode == 0x25CC:
            for anchor in glyph.anchors:
                if anchor.name == "aboveLC":
                    glyph.appendAnchor(
                        dict(name="markAbove", x=anchor.x,
                             y=anchor.y + offset))
                    glyph.appendAnchor(
                        dict(name="hamzaAbove",
                             x=anchor.x,
                             y=anchor.y + offset))
                if anchor.name == "belowLC":
                    glyph.appendAnchor(
                        dict(name="markBelow", x=anchor.x,
                             y=anchor.y - offset))
                    glyph.appendAnchor(
                        dict(name="hamzaBelow",
                             x=anchor.x,
                             y=anchor.y - offset))
        # Break loudly if we have duplicated glyph in Latin and Arabic.
        # TODO should check duplicated Unicode values as well
        assert glyph.name not in ufo, glyph.name
        ufo.insertGlyph(glyph)

    # Copy kerning and groups.
    ufo.groups.update(latin.groups)
    ufo.kerning.update(latin.kerning)

    # We don’t set these in the Arabic font, so we just copy the Latin’s.
    for attr in ("xHeight", "capHeight"):
        value = getattr(latin.info, attr)
        if value is not None:
            setattr(ufo.info, attr, getattr(latin.info, attr))

    # MutatorMath does not like multiple unicodes and will drop it entirely,
    # turning the glyph unencoded:
    # https://github.com/LettError/MutatorMath/issues/85
    for glyph in ufo:
        assert not " " in glyph.unicodes

    # Make sure we don’t have glyphs with the same unicode value
    unicodes = []
    for glyph in ufo:
        unicodes.extend(glyph.unicodes)
    duplicates = set([u for u in unicodes if unicodes.count(u) > 1])
    assert len(duplicates) == 0, "Duplicate unicodes: %s " % (
        ["%04X" % d for d in duplicates])

    # Make sure we have a fixed glyph order by using the original Arabic and
    # Latin glyph order, not whatever we end up with after adding glyphs.
    ufo.glyphOrder = sorted(ufo.glyphOrder, key=glyphOrder.index)

    return ufo
Beispiel #13
0
class MinifyUFO():
    def __init__(self, source, template=None, config=None):
        self.GDB = GlyphsLib(False, config)  # buildFea set to false
        self.srcUFO = self.sourceFont(source)
        self.UFO = Font()
        self.layers = {}

        if template is None:
            template = os.path.join(os.path.dirname(__file__), 'database/template.ufo')
        self.templateUFO = Font(template)

    def sourceFont(self, source):
        if source is None:
            raise Exception('font-file argument missing')

        font_type = source.split('.')[-1].lower()
        if font_type == "ufo":
            src = Font(source)
        elif font_type in  ["otf", "ttf", "woff", "woff2", "ttx", "pfa"]:
            import extractor
            src = Font()
            extractor.extractUFO(source, src)
        else:
            raise Exception('font-file in format ' + font_type + " is not supported")
        return src

    def build(self):
        self.copyFontInfo()
        self.createGlyphs()
        self.createAnchors()
        self.sortGlyphs()
        return self.UFO

    def getLayer(self, layer):
        layerName = "BG_layer_" + str(layer)
        if layerName not in self.layers.keys():
            newLayer = self.UFO.layers.newLayer(layerName)
            newLayer.color = Color("0,1,0,1")
            self.layers.update({layerName: newLayer})
        return self.layers[layerName]

    def copyFontInfo(self):
        data = self.srcUFO.getDataForSerialization()
        self.UFO.setDataFromSerialization({'info': data['info']})

    def createGlyphs(self):

        self.UFO.newGlyph('.notdef')
        missing = ''

        for glf in self.GDB.Master2Search:
            glfUnicode = int(self.GDB.Master2Unicode[glf], 16)

            print('')
            layer = 0
            stopAt = 'arAlef.fina.la'
            glfSrc = self.GDB.Master2Search[glf].split(',')
            if glf == stopAt:
                m = 1
            log = (glf + ' ' * 50)[0:20]
            if glf in self.GDB.MAPPING:
                try:
                    mgName = [self.GDB.MAPPING[glf]]
                    glyph = Glyph()
                    glyph.copyDataFromGlyph(self.srcUFO[mgName[0]])
                    glyph.name = glf
                    if layer == 0:
                        glyph.unicode = glfUnicode
                        glyph.unicodes = [glfUnicode]
                    else:
                        glyph.unicode = None
                    glyph.anchors = []
                    glyph.decomposeAllComponents()
                    if layer > 0:
                        currentLayer = self.getLayer(layer)
                        currentLayer.insertGlyph(glyph)
                    else:
                        self.UFO.insertGlyph(glyph)
                    layer += 1
                    # print(g + ' found :)' + '  L ' + str(layer))

                    gLog = log + (mgName[0] + ' ' * 50)[0:20]
                    print(gLog + '[' + str(layer) + ']  *')
                except:
                    pass
            for g in glfSrc:
                mgName = None
                gCode = None
                gLog = log + (g + ' ' * 50)[0:20]

                try:
                    try:
                        gCode = self.GDB.Prod2Decimal[g]
                        mgName = self.srcUFO.unicodeData[gCode]
                    except:
                        try:
                            mgName = [g]
                        except:
                            pass
                    glyph = Glyph()
                    glyph.copyDataFromGlyph(self.srcUFO[mgName[0]])
                    glyph.name = glf
                    if layer == 0:
                        glyph.unicode = glfUnicode
                        glyph.unicodes = [glfUnicode]
                    else:
                        glyph.unicode = None
                    glyph.anchors = []
                    glyph.decomposeAllComponents()
                    if layer > 0:
                        currentLayer = self.getLayer(layer)
                        currentLayer.insertGlyph(glyph)
                    else:
                        self.UFO.insertGlyph(glyph)
                    layer += 1
                    print(gLog + '[' + str(layer) + ']')
                except:
                    print(gLog + '[ ]')
                glyph = None
            if layer == 0:
                self.UFO.newGlyph(glf)
                missing += log + "\n"
        if len(missing) > 1:
            print('\n')
            print('=' * 60)
            print('Missing glyphes    ' + str(len(missing.splitlines())))
            print('=' * 60)
            print(missing)
            print('=' * 60)

    def createAnchors(self):
        factor = self.getFactorOfUPM()
        for g in self.UFO:
            try:
                sampleGlyph = self.templateUFO[g.name]
                g.anchors = copy.deepcopy(sampleGlyph.anchors)
                for point in g.anchors:
                    point.x *= factor
                    point.y *= factor
                for point in sampleGlyph.anchors:
                    xVal = point.x * factor
                    yVal = point.y * factor
                    c = Contour()
                    c.addPoint((xVal, yVal), name=point.name, segmentType="move")
                    g.appendContour(c)
            except:
                pass

    def getFactorOfUPM(self):
        templateUPM = self.templateUFO.info.unitsPerEm
        sourceFontUPM = self.UFO.info.unitsPerEm
        if sourceFontUPM > templateUPM:
            factor = float(templateUPM) /  float(sourceFontUPM)
        elif templateUPM > sourceFontUPM:
            factor = float(sourceFontUPM) /float(templateUPM)
        else:
            factor = 1
        return factor

    def sortGlyphs(self):
        self.UFO.lib['public.glyphOrder'].sort()
Beispiel #14
0
def merge(args):
    """Merges Arabic and Latin fonts together, and messages the combined font a
    bit. Returns the combined font."""

    ufo = Font(args.arabicfile)

    to_ufo_propagate_font_anchors(None, ufo)

    latin = Font(args.latinfile)

    ufo.lib[POSTSCRIPT_NAMES] = {}

    # Save original glyph order, used below.
    glyphOrder = ufo.glyphOrder + latin.glyphOrder

    # Generate production glyph names for Arabic glyphs, in case it differs
    # from working names. This will be used by ufo2ft to set the final glyph
    # names in the font file.
    for glyph in ufo:
        if glyph.unicode is not None:
            if glyph.unicode < 0xffff:
                postName = "uni%04X" % glyph.unicode
            else:
                postName = "u%06X" % glyph.unicode
            if postName != glyph.name:
                ufo.lib[POSTSCRIPT_NAMES][glyph.name] = postName

    # Merge Arabic and Latin features, making sure languagesystem statements
    # come first.
    features = ufo.features
    langsys = []
    statements = []
    for font in (ufo, latin):
        featurefile = os.path.join(font.path, "features.fea")
        fea = parser.Parser(featurefile, font.glyphOrder).parse()
        langsys += [s for s in fea.statements if isinstance(s, ast.LanguageSystemStatement)]
        statements += [s for s in fea.statements if not isinstance(s, ast.LanguageSystemStatement)]
        # We will regenerate kern, mark and mkmk features, and aalt is useless.
        statements = [s for s in statements if getattr(s, "name", None) not in ("aalt", "kern", "mark", "mkmk")]
        # These will be regenerated as well
        statements = [s for s in statements if not isinstance(s, ast.MarkClassDefinition)]
    # Drop tables in fea, we don’t want them.
    statements = [s for s in statements if not isinstance(s, ast.TableBlock)]
    # Make sure DFLT is the first.
    langsys = sorted(langsys, key=attrgetter("script"))
    fea.statements = langsys + statements
    features.text = fea.asFea()

    features.text += generateStyleSets(ufo)

    # Source Sans Pro has different advance widths for space and NBSP
    # glyphs, fix it.
    latin["nbspace"].width = latin["space"].width

    # Set Latin production names
    ufo.lib[POSTSCRIPT_NAMES].update(latin.lib[POSTSCRIPT_NAMES])

    # Copy Latin glyphs.
    for name in latin.glyphOrder:
        glyph = latin[name]
        # Remove anchors from spacing marks, otherwise ufo2ft will give them
        # mark glyph class which will cause HarfBuzz to zero their width.
        if glyph.unicode and unicodedata.category(unichr(glyph.unicode)) in ("Sk", "Lm"):
            for anchor in glyph.anchors:
                glyph.removeAnchor(anchor)
        # Add Arabic anchors to the dotted circle, we use an offset of 100
        # units because the Latin anchors are too close to the glyph.
        offset = 100
        if glyph.unicode == 0x25CC:
            for anchor in glyph.anchors:
                if anchor.name == "aboveLC":
                    glyph.appendAnchor(dict(name="markAbove", x=anchor.x, y=anchor.y + offset))
                    glyph.appendAnchor(dict(name="hamzaAbove", x=anchor.x, y=anchor.y + offset))
                if anchor.name == "belowLC":
                    glyph.appendAnchor(dict(name="markBelow", x=anchor.x, y=anchor.y - offset))
                    glyph.appendAnchor(dict(name="hamzaBelow", x=anchor.x, y=anchor.y - offset))
        # Break loudly if we have duplicated glyph in Latin and Arabic.
        # TODO should check duplicated Unicode values as well
        assert glyph.name not in ufo, glyph.name
        ufo.insertGlyph(glyph)

    # Copy kerning and groups.
    ufo.groups.update(latin.groups)
    ufo.kerning.update(latin.kerning)

    # We don’t set these in the Arabic font, so we just copy the Latin’s.
    for attr in ("xHeight", "capHeight"):
        value = getattr(latin.info, attr)
        if value is not None:
            setattr(ufo.info, attr, getattr(latin.info, attr))

    # Make sure we don’t have glyphs with the same unicode value
    unicodes = []
    for glyph in ufo:
        unicodes.extend(glyph.unicodes)
    duplicates = set([u for u in unicodes if unicodes.count(u) > 1])
    assert len(duplicates) == 0, "Duplicate unicodes: %s " % (["%04X" % d for d in duplicates])

    # Make sure we have a fixed glyph order by using the original Arabic and
    # Latin glyph order, not whatever we end up with after adding glyphs.
    ufo.glyphOrder = sorted(ufo.glyphOrder, key=glyphOrder.index)

    return ufo
Beispiel #15
0
class MaxifyUFO():
    def __init__(self, source, config=None):
        self.sourcesDir = os.sep.join(source.split(os.sep)[:-1])
        self.GDB = GlyphsLib(True, config)
        self.srcUFO = Font(source)
        self.UFO = Font()
        self.transFields = [
            "xScale", "xyScale", "yxScale", "yScale", "xOffset", "yOffset"
        ]

    def build(self):
        self.copyFontInfo()
        self.createGlyphs()
        self.removeOverlap()
        self.setFeatures()
        self.sortGlyphs()
        return self.UFO

    def copyFontInfo(self):
        data = self.srcUFO.getDataForSerialization()
        self.UFO.setDataFromSerialization({'info': data['info']})

    def setFeatures(self):
        featuresText = self.GDB.fea.fea_main
        userFeaFile = self.sourcesDir + os.sep + "font.fea"
        if os.path.isfile(userFeaFile):
            featuresText += self.GDB.get_file_content(userFeaFile)
        self.UFO.features.text = featuresText

    def removeOverlap(self):
        """Removes overlap by combining overlapping contours. Not really necessary,
        but some font rendering systems need this."""
        manager = BooleanOperationManager()
        for glyph in self.UFO:
            contours = list(glyph)
            glyph.clearContours()
            try:
                manager.union(contours, glyph.getPointPen())
            except:
                m = 1

    def createGlyphs(self):

        self.copyFundamentals()
        self.createWhiteSpacesGlyphs()

        subs = self.getSubsets()

        for gName, pgNames in subs.items():
            gModz = {}
            if gName == 'uni062B.medi.yeh':
                m = 1

            if gName in self.GDB.IRREGULAR.keys():
                gModz = self.GDB.IRREGULAR[gName]
            try:
                baseGlyph = self.UFO[pgNames[0]]
                masterGlyph = self.srcUFO[pgNames[0]]

                if not gName in self.UFO.keys():
                    glyph = self.addGlyph(gName, baseGlyph)

                if len(pgNames) == 1:
                    pass
                else:
                    for partName in pgNames[1:]:
                        pModz = []
                        if partName in gModz.keys():
                            pModz = gModz[partName]
                        partGlyph = self.UFO[partName]
                        masterPartGlyph = self.srcUFO[partName]

                        # add parts like Dot, small V, Hamza on the Base Glyph
                        partAnchors = [
                            a.name.replace("_", "", 1)
                            for a in masterPartGlyph.anchors
                            if a.name.startswith("_")
                        ]
                        baseAnchors = [
                            a.name for a in masterGlyph.anchors
                            if not a.name.startswith("_")
                        ]

                        anchorName = set(baseAnchors).intersection(partAnchors)
                        assert len(anchorName) > 0, (pgNames[0], partName,
                                                     partAnchors, baseAnchors)
                        anchorName = list(anchorName)[0]
                        partAnchor = [
                            a for a in masterPartGlyph.anchors
                            if a.name == "_" + anchorName
                        ][0]
                        baseAnchor = [
                            a for a in masterGlyph.anchors
                            if a.name == anchorName
                        ][0]
                        xoff = baseAnchor.x - partAnchor.x
                        yoff = baseAnchor.y - partAnchor.y
                        self.addComponent(glyph, partName, xoff, yoff, pModz)
                        self.updateAnchors(glyph, masterPartGlyph, xoff, yoff)

                        del baseAnchor, baseAnchors, a, xoff, yoff, partGlyph, anchorName, partName

            except:
                pass

    def getSubsets(self):
        subs = {}
        for gName, pgNames in self.GDB.Prod2Comp.items():
            rep = []
            for el in pgNames:
                rep.append(self.getUniName(el))
            subs[gName] = rep
        return subs

    def getUniName(self, name):
        if name in self.GDB.Master2Prod:
            return self.GDB.Master2Prod[name]
        else:
            return name

    def addGlyph(self, gName, baseGlyph):
        glyph = self.UFO.newGlyph(gName)
        if gName in self.GDB.Prod2Decimal:
            glyph.unicode = self.GDB.Prod2Decimal[gName]
        glyph.width = baseGlyph.width
        glyph.leftMargin = baseGlyph.leftMargin
        glyph.rightMargin = baseGlyph.rightMargin
        self.addComponent(glyph, baseGlyph.name)
        self.addAnchors(glyph, baseGlyph)
        return glyph

    def copyFundamentals(self):
        for g in self.srcUFO:
            if g.name in self.GDB.Master2Unicode:
                gName = self.GDB.Master2Prod[g.name]
                if gName == "uni0646.iso":
                    m = 1
                # print(gName)
                gUnicode = int(self.GDB.Master2Unicode[g.name], 16)
                g.name = gName
                g.unicode = gUnicode
                ng = copy.deepcopy(g)
                self.addAnchors(ng, g)
                self.UFO.insertGlyph(ng)

    def createWhiteSpacesGlyphs(self):
        spaceGlyph = self.UFO['space']
        try:
            spaceWidth = self.GDB.CONFIGS['info']['spaceWidth']
            spaceGlyph.width = int(spaceWidth)
        except:
            print('missing spaceWidth config value')

        space = spaceGlyph.width
        em = self.UFO.info.unitsPerEm

        # no-Break-space 0x00A0
        width = int(space / 2)
        self.createSpaceGlyphe(spaceGlyph, 'nbsp', '00A0', width)

        # en space
        width = int(em / 2)
        self.createSpaceGlyphe(spaceGlyph, 'enspace', '2002', width)

        # em space
        self.createSpaceGlyphe(spaceGlyph, 'emspace', '2003', em)

        # thinspace 0x2009
        width = int(space / 5)
        self.createSpaceGlyphe(spaceGlyph, 'thinspace', '2009', width)

        # hairspace 0x200A
        width = int(space / 7)
        self.createSpaceGlyphe(spaceGlyph, 'hairspace', '200A', width)

        # ZERO WIDTH SPACE 200B
        width = int(space / 7)
        self.createSpaceGlyphe(spaceGlyph, 'hairspace', '200B', 0)

        # ZWNJ 200C
        self.createSpaceGlyphe(spaceGlyph, 'zwnj', '200C', 0)

        # ZWJ 200D
        self.createSpaceGlyphe(spaceGlyph, 'zwj', '200D', 0)

        # lrm  200E
        self.createSpaceGlyphe(spaceGlyph, 'lrm', '200E', 0)

        # rlm 200F
        self.createSpaceGlyphe(spaceGlyph, 'rlm', '200F', 0)

        # ZERO WIDTH NO-BREAK SPACE FEFF
        width = int(space / 7)
        self.createSpaceGlyphe(spaceGlyph, 'zwnbsp', 'FEFF', 0)

        m = 1

    def createSpaceGlyphe(self, spGlyph, name, unicode, width):
        glyph = copy.deepcopy(spGlyph)
        glyph.width = int(width)
        glyph.name = name
        glyph.unicodes = tuple()
        glyph.unicode = int(unicode, 16)
        self.UFO.insertGlyph(glyph)

    def addComponent(self, glyph, name, xoff=0, yoff=0, pModz=[]):
        component = glyph.instantiateComponent()
        component.baseGlyph = name
        component.move((xoff, yoff))
        if len(pModz) > 0:
            trans = component.transformation
            dicts = [dict(zip(self.transFields, d)) for d in [trans]]
            ct = dicts[0]
            for prop in pModz:
                if prop in ("xOffset", "yOffset"):
                    ct[prop] += float(pModz[prop])
                else:
                    ct[prop] = float(pModz[prop])
            newProps = []
            for pn in self.transFields:
                newProps.append(ct[pn])
                component.transformation = tuple(newProps)
        glyph.appendComponent(component)

    def addAnchors(self, glyph, base):
        anchors = base.anchors
        glyph.clearAnchors()
        if glyph.name == 'uniE272':
            m = 1
        markAnchors = [
            'markAbove', 'markBelow', 'markAbove_1', 'markAbove_2',
            'markBelow_1', 'markBelow_2', '_markAbove', '_markBelow',
            '_markAbove_1', '_markAbove_2', '_markBelow_1', '_markBelow_2',
            '_hamzaAbove', 'hamzaAbove', '_hamzaBelow', 'hamzaBelow'
            # 'markAboveMark','markBelowMark','_markAboveMark','_markBelowMark'
        ]
        if len(anchors):
            for anchor in anchors:
                if anchor.name in markAnchors:
                    anc = glyph.instantiateAnchor()
                    anc.x = anchor.x
                    anc.y = anchor.y
                    anc.name = anchor.name
                    glyph.appendAnchor(anc)

                    c = Contour()
                    c.addPoint((anchor.x, anchor.y),
                               name=anchor.name,
                               segmentType="move")
                    glyph.appendContour(c)

                else:
                    continue

    def updateAnchors(self, glyph, base, x, y):
        anchors = base.anchors
        if glyph.name == 'shaddaKasra':
            m = 1
        if len(anchors):
            for anchor in anchors:
                if anchor.name == 'markAbove' or anchor.name == 'markAboveDot' or anchor.name == 'markAboveMark':
                    for ganchor in glyph.anchors:
                        if ganchor.name == "markAbove":
                            ganchor.x = x + anchor.x
                            ganchor.y = y + anchor.y
                if anchor.name == 'markAbove_2':
                    for ganchor in glyph.anchors:
                        if ganchor.name == "markAbove_2":
                            ganchor.x = x + anchor.x
                            ganchor.y = y + anchor.y
                if anchor.name == 'markBelow' or anchor.name == 'markBelowDot' or anchor.name == 'markBelowMark':
                    if glyph.name in [
                            'uni062C', 'uni062C.fina', 'uni062C.isol',
                            'uni0686.fina', 'uni0686.isol', 'uni0686'
                    ]:
                        continue
                    for ganchor in glyph.anchors:
                        if ganchor.name == "markBelow":
                            ganchor.x = x + anchor.x
                            ganchor.y = y + anchor.y
                # shadda with kasra or kasratan, will move above
                if anchor.name == '_markAboveAlt':
                    for ganchor in glyph.anchors:
                        if ganchor.name == "_markAbove":
                            ganchor.x = x + anchor.x
                            ganchor.y = y + anchor.y
                else:
                    continue

    def sortGlyphs(self):
        self.UFO.lib['public.glyphOrder'].sort()
Beispiel #16
0
def merge(args):
    """Merges Arabic and Latin fonts together, and messages the combined font a
    bit. Returns the combined font."""

    ufo = Font(args.arabicfile)

    latin = Font(args.latinfile)
    # Parse the GlyphOrderAndAliasDB file for Unicode values and production
    # glyph names of the Latin glyphs.
    goadb = GOADBParser(os.path.dirname(args.latinfile) + "/../GlyphOrderAndAliasDB")

    ufo.lib[POSTSCRIPT_NAMES] = {}

    # Generate production glyph names for Arabic glyphs, in case it differs
    # from working names. This will be used by ufo2ft to set the final glyph
    # names in the font file.
    for glyph in ufo:
        if glyph.unicode is not None:
            if glyph.unicode < 0xffff:
                postName = "uni%04X" % glyph.unicode
            else:
                postName = "u%06X" % glyph.unicode
            if postName != glyph.name:
                ufo.lib[POSTSCRIPT_NAMES][glyph.name] = postName

    # Populate the font’s feature text, we keep our main feature file out of
    # the UFO to share it between the fonts.
    features = ufo.features
    with open(args.feature_file) as feafile:
        fea = feafile.read()
        # Set Latin language system, ufo2ft will use it when generating kern
        # feature.
        features.text += fea.replace("#{languagesystems}", "languagesystem latn dflt;")
    features.text += generateStyleSets(ufo)

    for glyph in latin:
        if glyph.name in goadb.encodings:
            uni = goadb.encodings[glyph.name]
            # Source Sans Pro has different advance widths for space and NBSP
            # glyphs, so we drop the later, and map both Unicode characters to
            # the space glyph.
            if uni == 0x00A0: # NBSP
                continue
            glyph.unicode = uni
            if uni == 0x0020: # space
                glyph.unicodes = glyph.unicodes + [0x00A0]

    glyphs, components = collectGlyphs(latin, args.latin_subset)

    counter = Counter(components)
    uniqueComponents = set()
    for name in counter:
        if name not in glyphs:
            latin[name].unicode = None
        if counter[name] == 1:
            uniqueComponents.add(name)
        else:
            glyphs.add(name)

    # Set Latin production names
    ufo.lib[POSTSCRIPT_NAMES].update(goadb.names)

    # Copy Latin glyphs.
    for name in glyphs:
        glyph = latin[name]
        for component in glyph.components:
            if component.baseGlyph in uniqueComponents:
                glyph.decomposeComponent(component)
        # Remove anchors from spacing marks, otherwise ufo2ft will give them
        # mark glyph class which will cause HarfBuzz to zero their width.
        if glyph.unicode and unicodedata.category(unichr(glyph.unicode)) in ("Sk", "Lm"):
            for anchor in glyph.anchors:
                glyph.removeAnchor(anchor)
        # Add Arabic anchors to the dotted circle, we use an offset of 100
        # units because the Latin anchors are too close to the glyph.
        offset = 100
        if glyph.unicode == 0x25CC:
            for anchor in glyph.anchors:
                if anchor.name == "aboveLC":
                    glyph.appendAnchor(dict(name="markAbove", x=anchor.x, y=anchor.y + offset))
                    glyph.appendAnchor(dict(name="hamzaAbove", x=anchor.x, y=anchor.y + offset))
                if anchor.name == "belowLC":
                    glyph.appendAnchor(dict(name="markBelow", x=anchor.x, y=anchor.y - offset))
                    glyph.appendAnchor(dict(name="hamzaBelow", x=anchor.x, y=anchor.y - offset))
        # Break loudly if we have duplicated glyph in Latin and Arabic.
        # TODO should check duplicated Unicode values as well
        assert glyph.name not in ufo, glyph.name
        ufo.insertGlyph(glyph)

    # Copy kerning and groups.
    for group in latin.groups:
        ufo.groups[group] = latin.groups[group]
    for kern in latin.kerning:
        ufo.kerning[kern] = latin.kerning[kern]

    # We don’t set these in the Arabic font, so we just copy the Latin’s.
    for attr in ("xHeight", "capHeight"):
        value = getattr(latin.info, attr)
        if value is not None:
            setattr(ufo.info, attr, getattr(latin.info, attr))

    return ufo
Beispiel #17
0
    return OrderedDict(
        (script, tuple(langs)) for script, langs in scripts.items())


if __name__ == '__main__':
    from defcon import Font

    font = Font(path=sys.argv[2])
    for mergePath in sys.argv[3:]:
        merge = Font(path=mergePath)
        # merge glyphs
        for name in merge.keys():
            glyph = merge[name]
            # had an error related to anchors, but I don't need anchors here
            glyph.anchors = []
            font.insertGlyph(glyph, name=name)
        # merge groups
        font.groups.update(merge.groups)
        # merge kerning
        font.kerning.update(merge.kerning)

    # scripts = {'arab': ('dflt', 'ARA ', 'URD ', 'FAR '), 'latn': ('dflt', 'TRK ')}
    # scripts = scriptsFromFea(sys.argv[1])
    # scripts = {'arab': ('dflt', ), 'latn': ('dflt', )}
    scripts = {
        'arab': ('dflt', 'ARA ', 'URD ', 'FAR '),
        'latn': ('dflt', 'AZE', 'CRT', 'KAZ', 'MOL', 'ROM', 'TAT', 'TRK')
    }

    kfw = KernFeatureWriterWithHorizontalDirections(font, scripts)
    print(kfw.write())
Beispiel #18
0
    def stub(r, rs):
        if rs.cmd == "rf":
        #if ufo_path not in rs.watch_soft_mods:
            os.system(f"robofont -p {stub.codepath}")

        ufo = Font(str(ufo_path))

        if False:
            return [
                DATPen().glyph(ufo[ch]).f(0).align(r),
                #DATPen().glyph(ufo[ch]).skeleton().s(hsl(0.5, s=1, l=0.3))
            ]

        all_points = [[]]
        for g in rs.input_history.strokes(lambda g: g.action in ["down", "cmd"]):
            if g.action == "cmd":
                if g.position() == glfw.KEY_B:
                    all_points.append([])
                elif g.position() == glfw.KEY_C:
                    try:
                        all_points[-1][-1] = all_points[-1][-1][0:-1]
                        all_points[-1][-1].append(all_points[-1][-1][0].offset(1, 1))
                        #return DATPen().rect(all_points[-1][-1][0].rect(30, 30))
                        all_points.append([])
                    except IndexError:
                        pass
                continue
            if len(g) > 0:
                ps = []
                for p in g:
                    ps.append(p.position)
                all_points[-1].append(ps)
            else:
                #print(g.items)
                pass
        
        for i, points in enumerate(all_points):
            for j, path in enumerate(points):
                for k, pt in enumerate(path):
                    #print(pt.round_to(100))
                    #npt = pt.round_to(100)
                    #print(npt)
                    all_points[i][j][k] = pt.round_to(10)

        dps = DATPenSet()
        for points in all_points:
            out = DATPenSet()
            dp = DATPen()

            for idx, path in enumerate(points):
                if len(path) < 3:
                    for pidx, pt in enumerate(path):
                        if idx == 0 and pidx == 0:
                            dp.moveTo(pt)
                        else:
                            dp.lineTo(pt)
                else:
                    #print(path)
                    try:
                        bpp = beziers.path.BezierPath.fromPoints([beziers.point.Point(p.x, p.y) for p in path], error=1000).smooth().addExtremes()
                        cdp = DATPen.from_cbp([bpp]).s(0).sw(15).f(None)
                        cdp.value = cdp.value[0:-1]
                        mv, mvpts = cdp.value[0]
                        if idx > 0:
                            cdp.value[0] = ("lineTo", mvpts)
                        dp.record(cdp)
                    except IndexError:
                        print(path)
            
            
            #dp = DATPen().f(0).record(out).connect()
            #dp.filter(lambda i, mv, ps: mv not in ["endPath"])
            #dp = out.pen().connect()
            #try:
            #    dp.value[-1] = ("closePath", [])
            #except IndexError:
            #    pass
            dps += dp
            #dps += dp
            #dps += out.pen()
        
        if rs.keylayer == Keylayer.Default:
            return dps.pen().f(0).s(0).sw(5).color_phototype(r, blur=5, cut=150)
        else:
            #print(dps.pen().value[-1])
            #print(len(dps.pen().value))
            if rs.cmd == "save":
                for dp in dps:
                    dp.value.append(("closePath", []))
                #from pprint import pprint
                #pprint(dps.pen().value)
                g = dps.pen().to_glyph()
                ufo.insertGlyph(g, name=ch)
                ufo.save()
                # now the robofont script
            return [
                dps.pen().f(0).s(0).sw(5).color_phototype(r, blur=5, cut=150),
                dps.f(None).s(hsl(0.9, s=1, l=0.8)).sw(3),
                dps.pen().skeleton()
            ]
Beispiel #19
0
def merge(args):
    arabic = Font(args.arabicfile)

    latin = Font(args.latinfile)

    addPlaceHolders(arabic)

    unicodes = parseSubset(args.latin_subset)
    for glyph in arabic:
        unicodes.extend(glyph.unicodes)

    latin_locl = ""
    for name in latin.glyphOrder:
        glyph = latin[name]
        if name in arabic:
            glyph.unicode = None
            glyph.name = name + ".latn"
            latin_locl += "sub %s by %s;" % (name, glyph.name)
        arabic.insertGlyph(glyph)

    for attr in ("xHeight", "capHeight"):
        value = getattr(latin.info, attr)
        if value is not None:
            setattr(arabic.info, attr, getattr(latin.info, attr))

    arabic.features.text += latin.features.text

    if latin_locl:
        arabic.features.text += """
feature locl {
  lookupflag IgnoreMarks;
  script latn;
  %s
} locl;
""" % latin_locl

    for ch in [(ord(u'؟'), "question")]:
        arGlyph = arabic.newGlyph("uni%04X" % ch[0])
        arGlyph.unicode = ch[0]
        enGlyph = arabic[ch[1]]
        component = Component()
        component.transformation = tuple(Transform().scale(-1, 1))
        component.baseGlyph = enGlyph.name
        arGlyph.appendComponent(component)
        arGlyph.leftMargin = enGlyph.rightMargin
        arGlyph.rightMargin = enGlyph.leftMargin
        unicodes.append(arGlyph.unicode)

    arabic.lib[MADA_UNICODES] = unicodes

    # Set metadata
    arabic.info.versionMajor, arabic.info.versionMinor = map(
        int, args.version.split("."))

    copyright = u"Copyright © 2015-%s The Reem Kufi Project Authors." % datetime.now(
    ).year

    arabic.info.copyright = copyright

    arabic.info.openTypeNameDesigner = u"Khaled Hosny"
    arabic.info.openTypeNameLicenseURL = u"http://scripts.sil.org/OFL"
    arabic.info.openTypeNameLicense = u"This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL"
    arabic.info.openTypeNameDescription = u"Reem Kufi is a Fatimid-style decorative Kufic typeface as seen in the historical mosques of Cairo. Reem Kufi is based on the Kufic designs of the great Arabic calligrapher Mohammed Abdul Qadir who revived this art in the 20th century and formalised its rules."
    arabic.info.openTypeNameSampleText = u"ريم على القاع بين البان و العلم   أحل سفك دمي في الأشهر الحرم"

    return arabic