Beispiel #1
0
def merge(args):
    arabic = fontforge.open(args.arabicfile)
    arabic.encoding = "Unicode"

    with open(args.feature_file) as feature_file:
        features = string.Template(feature_file.read())
        gpos = arabic.generateFeatureString()
        for lookup in arabic.gpos_lookups:
            arabic.removeLookup(lookup)
        arabic.mergeFeatureString(features.substitute(GPOS=gpos))

    build_encoded(arabic)

    latin = fontforge.open(args.latinfile)
    latin.encoding = "Unicode"
    latin.em = arabic.em

    latin_locl = ""
    for glyph in latin.glyphs():
        if glyph.color == 0xff0000:
            latin.removeGlyph(glyph)
        else:
            if glyph.glyphname in arabic:
                name = glyph.glyphname
                glyph.unicode = -1
                glyph.glyphname = name + ".latin"
                if not latin_locl:
                    latin_locl = "feature locl {lookupflag IgnoreMarks; script latn;"
                latin_locl += "sub %s by %s;" % (name, glyph.glyphname)

    arabic.mergeFonts(latin)
    if latin_locl:
        latin_locl += "} locl;"
        arabic.mergeFeatureString(latin_locl)

    # Set metadata
    arabic.version = args.version
    copyright = 'Copyright © 2015-%s The Aref Ruqaa Project Authors, with Reserved Font Name "EURM10".' % datetime.now(
    ).year

    arabic.copyright = copyright.replace("©", "(c)")

    en = "English (US)"
    arabic.appendSFNTName(en, "Copyright", copyright)
    arabic.appendSFNTName(en, "Designer", "Aboullah Aref")
    arabic.appendSFNTName(en, "License URL", "http://scripts.sil.org/OFL")
    arabic.appendSFNTName(
        en, "License",
        '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.appendSFNTName(
        en, "Descriptor",
        "Aref Ruqaa is an Arabic typeface that aspires to capture the essence of \
the classical Ruqaa calligraphic style.")
    arabic.appendSFNTName(en, "Sample Text",
                          "الخط هندسة روحانية ظهرت بآلة جسمانية")

    return arabic
Beispiel #2
0
def merge(args):
    arabic = fontforge.open(args.arabicfile)
    arabic.encoding = "Unicode"
    arabic.mergeFeature(args.feature_file)

    latin = fontforge.open(args.latinfile)
    latin.encoding = "Unicode"
    scale = arabic["arAlef.isol"].width / latin["space"].width
    latin.em = int(math.ceil(scale * latin.em))

    latin_locl = ""
    for glyph in latin.glyphs():
        if glyph.glyphclass == "mark":
            glyph.width = latin["A"].width
        if glyph.color == 0xff0000:
            latin.removeGlyph(glyph)
        else:
            if glyph.glyphname in arabic:
                name = glyph.glyphname
                glyph.unicode = -1
                glyph.glyphname = name + ".latin"
                if not latin_locl:
                    latin_locl = "feature locl {lookupflag IgnoreMarks; script latn;"
                latin_locl += "sub %s by %s;" % (name, glyph.glyphname)

    arabic.mergeFonts(latin)
    if latin_locl:
        latin_locl += "} locl;"
        arabic.mergeFeatureString(latin_locl)

    zeromarks(arabic)

    # Set metadata
    arabic.version = args.version

    copyright = 'Copyright © 2015-%s The Amiri Typewriter Project Authors, with Reserved Font Name "Fira".' % datetime.now(
    ).year

    arabic.copyright = copyright.replace("©", "(c)")

    en = "English (US)"
    arabic.appendSFNTName(en, "Copyright", copyright)
    arabic.appendSFNTName(en, "Designer", "Khaled Hosny")
    arabic.appendSFNTName(en, "License URL", "http://scripts.sil.org/OFL")
    arabic.appendSFNTName(
        en, "License",
        '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.appendSFNTName(
        en, "Descriptor",
        "Amiri Typewriter is an Arabic monospaced font family inspired by the type of mechanical Arabic typewriters."
    )
    arabic.appendSFNTName(en, "Sample Text",
                          "الخط هندسة روحانية ظهرت بآلة جسمانية")

    return arabic
Beispiel #3
0
def merge(args):
    arabic = fontforge.open(args.arabicfile)
    arabic.encoding = "Unicode"

    with open(args.feature_file) as feature_file:
        features = string.Template(feature_file.read())
        gpos = arabic.generateFeatureString()
        for lookup in arabic.gpos_lookups:
            arabic.removeLookup(lookup)
        arabic.mergeFeatureString(features.substitute(GPOS=gpos))

    build_encoded(arabic)

    latin = fontforge.open(args.latinfile)
    latin.encoding = "Unicode"
    latin.em = arabic.em

    latin_locl = ""
    for glyph in latin.glyphs():
        if glyph.color == 0xff0000:
            latin.removeGlyph(glyph)
        else:
            if glyph.glyphname in arabic:
                name = glyph.glyphname
                glyph.unicode = -1
                glyph.glyphname = name + ".latin"
                if not latin_locl:
                    latin_locl = "feature locl {lookupflag IgnoreMarks; script latn;"
                latin_locl += "sub %s by %s;" % (name, glyph.glyphname)

    arabic.mergeFonts(latin)
    if latin_locl:
        latin_locl += "} locl;"
        arabic.mergeFeatureString(latin_locl)

    # Set metadata
    arabic.version = args.version
    years = datetime.now().year == 2015 and 2015 or "2015-%s" % datetime.now().year

    arabic.copyright = ". ".join(["Portions copyright © %s, Khaled Hosny (<*****@*****.**>)" % years,
                              "Portions " + latin.copyright[0].lower() + latin.copyright[1:].replace("(c)", "©")])

    en = "English (US)"
    arabic.appendSFNTName(en, "Designer", "Abdoulla Aref")
    arabic.appendSFNTName(en, "License URL", "http://scripts.sil.org/OFL")
    arabic.appendSFNTName(en, "License", 'This Font Software is licensed under the SIL Open Font License, Version 1.1. \
This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR \
CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License \
for the specific language, permissions and limitations governing your use of \
this Font Software.')
    arabic.appendSFNTName(en, "Descriptor", "Aref Ruqaa is an Arabic typeface that aspires to capture the essence of \
the classical Ruqaa calligraphic style.")
    arabic.appendSFNTName(en, "Sample Text", "الخط هندسة روحانية ظهرت بآلة جسمانية")

    return arabic
Beispiel #4
0
def merge(args):
    arabic = fontforge.open(args.arabicfile)
    arabic.encoding = "Unicode"

    with open(args.feature_file) as feature_file:
        fea = feature_file.read()
        fea += generate_anchors(arabic)
        arabic.mergeFeatureString(fea)

    build_encoded(arabic)

    auto_hint(arabic)

    latin = fontforge.open(args.latinfile)
    latin.encoding = "Unicode"
    latin.em = arabic.em

    latin_locl = ""
    for glyph in latin.glyphs():
        if glyph.color == 0xff0000:
            latin.removeGlyph(glyph)
        else:
            if glyph.glyphname in arabic:
                name = glyph.glyphname
                glyph.unicode = -1
                glyph.glyphname = name + ".latin"
                if not latin_locl:
                    latin_locl = "feature locl {lookupflag IgnoreMarks; script latn;"
                latin_locl += "sub %s by %s;" % (name, glyph.glyphname)

    arabic.mergeFonts(latin)
    if latin_locl:
        latin_locl += "} locl;"
        arabic.mergeFeatureString(latin_locl)

    # Set metadata
    arabic.version = args.version
    years = datetime.now().year == 2015 and 2015 or "2015-%s" % datetime.now().year

    arabic.copyright = ". ".join(["Portions copyright © %s, Khaled Hosny (<*****@*****.**>)" % years,
                              "Portions " + latin.copyright.replace("(c)", "©").replace("Digitized data ", "")])

    en = "English (US)"
    arabic.appendSFNTName(en, "Designer", "Khaled Hosny")
    arabic.appendSFNTName(en, "License URL", "http://scripts.sil.org/OFL")
    arabic.appendSFNTName(en, "License", 'This Font Software is licensed under the SIL Open Font License, Version 1.1. \
This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR \
CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License \
for the specific language, permissions and limitations governing your use of \
this Font Software.')
    arabic.appendSFNTName(en, "Descriptor", "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.appendSFNTName(en, "Sample Text", "ريم على القاع بين البان و العلم   أحل سفك دمي في الأشهر الحرم")

    return arabic
Beispiel #5
0
def merge(args):
    arabic = fontforge.open(args.arabicfile)
    arabic.encoding = "Unicode"
    arabic.mergeFeature(args.feature_file)

    latin = fontforge.open(args.latinfile)
    latin.encoding = "Unicode"
    scale = arabic["arAlef.isol"].width / latin["space"].width
    latin.em = int(math.ceil(scale * latin.em))

    latin_locl = ""
    for glyph in latin.glyphs():
        if glyph.glyphclass == "mark":
            glyph.width = latin["A"].width
        if glyph.color == 0xff0000:
            latin.removeGlyph(glyph)
        else:
            if glyph.glyphname in arabic:
                name = glyph.glyphname
                glyph.unicode = -1
                glyph.glyphname = name + ".latin"
                if not latin_locl:
                    latin_locl = "feature locl {lookupflag IgnoreMarks; script latn;"
                latin_locl += "sub %s by %s;" % (name, glyph.glyphname)

    arabic.mergeFonts(latin)
    if latin_locl:
        latin_locl += "} locl;"
        arabic.mergeFeatureString(latin_locl)

    zeromarks(arabic)

    # Set metadata
    arabic.version = args.version

    copyright = 'Copyright © 2015-%s The Amiri Typewriter Project Authors, with Reserved Font Name "Fira".' % datetime.now().year

    arabic.copyright = copyright.replace("©", "(c)")

    en = "English (US)"
    arabic.appendSFNTName(en, "Copyright", copyright)
    arabic.appendSFNTName(en, "Designer", "Khaled Hosny")
    arabic.appendSFNTName(en, "License URL", "http://scripts.sil.org/OFL")
    arabic.appendSFNTName(en, "License", '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.appendSFNTName(en, "Descriptor", "Amiri Typewriter is an Arabic monospaced font family inspired by the type of mechanical Arabic typewriters.")
    arabic.appendSFNTName(en, "Sample Text", "الخط هندسة روحانية ظهرت بآلة جسمانية")

    return arabic
def main_cleanClass(classname, fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}
    classFeatureFile = featureFiles['sources/classes.fea']
    new_klass, _, removed = _cleanClass(classname, font, classFeatureFile, featureFiles)
    print('removed', removed)
    print('{name} = [ {classes} ];'.format(name=classname,classes=' '.join(new_klass)))
Beispiel #7
0
def makeDesktop(infile, outfile, feafile, version, latin=True, generate=True):
    font = fontforge.open(infile)
    font.encoding = "UnicodeFull"  # avoid a crash if compact was set

    updateInfo(font, version)

    # remove anchors that are not needed in the production font
    cleanAnchors(font)

    #makeOverUnderline(font)

    # sample text to be used by font viewers
    sample = 'صِفْ خَلْقَ خَوْدٍ كَمِثْلِ ٱلشَّمْسِ إِذْ بَزَغَتْ يَحْظَىٰ ٱلضَّجِيعُ بِهَا نَجْلَاءَ مِعْطَارِ.'

    for lang in ('Arabic (Egypt)', 'English (US)'):
        font.appendSFNTName(lang, 'Sample Text', sample)

    if latin:
        mergeLatin(font, feafile)
        makeNumerators(font)

        # we want to merge features after merging the latin font because many
        # referenced glyphs are in the latin font
        mergeFeatures(font, feafile)

    if generate:
        generateFont(font, outfile)
    else:
        return font
Beispiel #8
0
def makeDesktop(infile, outfile, feafile, version, latin=True, generate=True):
    font = fontforge.open(infile)
    font.encoding = "UnicodeBmp"  # avoid a crash if compact was set

    if version:
        setVersion(font, version)

    # remove anchors that are not needed in the production font
    cleanAnchors(font)

    # makeOverUnderline(font)

    # sample text to be used by font viewers
    sample = "صِفْ خَلْقَ خَوْدٍ كَمِثْلِ ٱلشَّمْسِ إِذْ بَزَغَتْ يَحْظَىٰ ٱلضَّجِيعُ بِهَا نَجْلَاءَ مِعْطَارِ."

    for lang in ("Arabic (Egypt)", "English (US)"):
        font.appendSFNTName(lang, "Sample Text", sample)

    if latin:
        mergeLatin(font, feafile)

        # we want to merge features after merging the latin font because many
        # referenced glyphs are in the latin font
        mergeFeatures(font, feafile)

    if generate:
        generateFont(font, outfile)
    else:
        return font
def main_cleanClass(classname, fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}
    classFeatureFile = featureFiles['sources/classes.fea']
    new_klass, _, removed = _cleanClass(classname, font, classFeatureFile,
                                        featureFiles)
    print('removed', removed)
    print('{name} = [ {classes} ];'.format(name=classname,
                                           classes=' '.join(new_klass)))
def main_features(fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}

    marked = getMarkedGlyphs(font)
    table = sorted([(countNameInFeatures(glyph.glyphname, featureFiles), glyph.glyphname) for glyph in marked], reverse=True)

    for (total, perFile, _), name in table:
        if not total: continue
        print('-' * 20)
        print(name, 'total:', total)
        for filename, count in perFile:
            if not count: continue
            print(str(count).ljust(5), ' | ', filename)
Beispiel #11
0
def makeCss(infiles, outfile):
    """Builds a CSS file for the entire font family."""

    css = ""

    for f in infiles.split():
        base = os.path.splitext(os.path.basename(f))[0]
        font = fontforge.open(f)
        font.encoding = "UnicodeBmp"  # avoid a crash if compact was set
        css += genCSS(font, base)
        font.close()

    out = open(outfile, "w")
    out.write(css)
    out.close()
def main(fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}
    state = _State(font, featureFiles)
    removals = state.findUnaccessibleGlyphs()

    info('to be removed:', len(removals), 'of', len(font), 'new length: ', len(font) - len(removals))

    if not removals:
        info('nothing to do')
        return;

    for name in removals:
        font.removeGlyph(name)
    font.save()
Beispiel #13
0
def makeCss(infiles, outfile):
    """Builds a CSS file for the entire font family."""

    css = ""

    for f in infiles.split():
        base = os.path.splitext(os.path.basename(f))[0]
        font = fontforge.open(f)
        font.encoding = "UnicodeBmp"  # avoid a crash if compact was set
        css += genCSS(font, base)
        font.close()

    out = open(outfile, "w")
    out.write(css)
    out.close()
def main(fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}
    state = _State(font, featureFiles)
    removals = state.findUnaccessibleGlyphs()

    info('to be removed:', len(removals), 'of', len(font), 'new length: ',
         len(font) - len(removals))

    if not removals:
        info('nothing to do')
        return

    for name in removals:
        font.removeGlyph(name)
    font.save()
def main_blockers(fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}

    marked = getMarkedGlyphs(font)
    dependents = getDependents(marked, font)
    table = sorted([getTableRow(glyph, dependents, featureFiles) for glyph in marked], reverse=True)

    headers = ['unicode', 'is exception', '1-hard deps', 'n-hard deps', 'soft deps', 'in fea', 'name']
    headerSizes = [len(name) for name in headers]
    print(' | '.join(headers))
    for row in table:
        # skip rows that would be removed by removeInaccessibleGlyphs.py
        if tuple(row[:-1]) == (False, False, 0, 0, 0,False): continue
        index = iter(xrange(len(headers)))
        print(' | '.join([str(item).rjust(headerSizes[index.next()]) for item in row]))
Beispiel #16
0
def makeWeb(infile, outfile):
    """If we are building a web version then try to minimise file size"""

    # "short-post" generates a post table without glyph names to save some KBs
    # since glyph names are only needed for PDF's as readers use them to
    # "guess" characters when copying text, which is of little use in web fonts.
    flags = ("opentype", "short-post", "omit-instructions")

    fontforge.setPrefs("PreserveTables", "COLR,CPAL")

    font = fontforge.open(infile)
    font.encoding = "UnicodeBmp" # avoid a crash if compact was set

    # removed compatibility glyphs that of little use on the web
    compat_ranges = (
            (0xfb50, 0xfbb1),
            (0xfbd3, 0xfd3d),
            (0xfd50, 0xfdf9),
            (0xfdfc, 0xfdfc),
            (0xfe70, 0xfefc),
            )

    for glyph in font.glyphs():
        for i in compat_ranges:
            start = i[0]
            end = i[1]
            if start <= glyph.unicode <= end:
                font.removeGlyph(glyph)
                break

    tmpfile = mkstemp(suffix=os.path.basename(outfile))[1]
    font.generate(tmpfile, flags=flags)
    font.close()

    # now open in fontTools
    from fontTools.ttLib import TTFont
    ftfont = TTFont(tmpfile)

    # force compiling tables by fontTools, saves few tens of KBs
    for tag in ftfont.keys():
        if hasattr(ftfont[tag], "compile"):
            ftfont[tag].compile(ftfont)

    ftfont.save(outfile)
    ftfont.close()

    os.remove(tmpfile)
Beispiel #17
0
def makeWeb(infile, outfile):
    """If we are building a web version then try to minimise file size"""

    # "short-post" generates a post table without glyph names to save some KBs
    # since glyph names are only needed for PDF's as readers use them to
    # "guess" characters when copying text, which is of little use in web fonts.
    flags = ("opentype", "short-post", "omit-instructions")

    fontforge.setPrefs("PreserveTables", "COLR,CPAL")

    font = fontforge.open(infile)
    font.encoding = "UnicodeBmp"  # avoid a crash if compact was set

    # removed compatibility glyphs that of little use on the web
    compat_ranges = (
        (0xfb50, 0xfbb1),
        (0xfbd3, 0xfd3d),
        (0xfd50, 0xfdf9),
        (0xfdfc, 0xfdfc),
        (0xfe70, 0xfefc),
    )

    for glyph in font.glyphs():
        for i in compat_ranges:
            start = i[0]
            end = i[1]
            if start <= glyph.unicode <= end:
                font.removeGlyph(glyph)
                break

    tmpfile = mkstemp(suffix=os.path.basename(outfile))[1]
    font.generate(tmpfile, flags=flags)
    font.close()

    # now open in fontTools
    from fontTools.ttLib import TTFont
    ftfont = TTFont(tmpfile)

    # force compiling tables by fontTools, saves few tens of KBs
    for tag in ftfont.keys():
        if hasattr(ftfont[tag], "compile"):
            ftfont[tag].compile(ftfont)

    ftfont.save(outfile)
    ftfont.close()

    os.remove(tmpfile)
def main_features(fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}

    marked = getMarkedGlyphs(font)
    table = sorted(
        [(countNameInFeatures(glyph.glyphname, featureFiles), glyph.glyphname)
         for glyph in marked],
        reverse=True)

    for (total, perFile, _), name in table:
        if not total: continue
        print('-' * 20)
        print(name, 'total:', total)
        for filename, count in perFile:
            if not count: continue
            print(str(count).ljust(5), ' | ', filename)
def main_cleanable(fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}
    classFeatureFile = featureFiles['sources/classes.fea']

    classes = []
    for number, line in enumerate(classFeatureFile):
        index = line.find('=')
        if index == -1:
            index = line.find(' ')
        if index <= 0:
            continue
        classname = line[:index-1].strip();
        if not isClassName(classname):
            continue
        new_klass, _, removed = _cleanClass(classname, font, classFeatureFile, featureFiles)
        if removed:
            print (classname, 'removed:', removed, 'empty:', not len(new_klass))
def main_cleanable(fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}
    classFeatureFile = featureFiles['sources/classes.fea']

    classes = []
    for number, line in enumerate(classFeatureFile):
        index = line.find('=')
        if index == -1:
            index = line.find(' ')
        if index <= 0:
            continue
        classname = line[:index - 1].strip()
        if not isClassName(classname):
            continue
        new_klass, _, removed = _cleanClass(classname, font, classFeatureFile,
                                            featureFiles)
        if removed:
            print(classname, 'removed:', removed, 'empty:', not len(new_klass))
def main_replaceReferences(fontLocation, oldName, newName):
    font = fontforge.open(fontLocation)

    # just to check if the names exist
    glyph = font[oldName]
    replacement = font[newName]

    total, perGlyph = replaceReference(font, oldName, newName)

    print('Details:')
    print('-'*50)
    for name, number in perGlyph:
        print(str(number).rjust(5), '|', name)
    print('Replaced references to "{oldName}" with "{newName}"'.format(oldName=oldName,newName=newName))
    print('Changed:', len(perGlyph),'glyphs')
    print('Total:', total, 'references replaced')

    if total != 0:
        font.save();
Beispiel #22
0
def main_replaceReferences(fontLocation, oldName, newName):
    font = fontforge.open(fontLocation)

    # just to check if the names exist
    glyph = font[oldName]
    replacement = font[newName]

    total, perGlyph = replaceReference(font, oldName, newName)

    print('Details:')
    print('-' * 50)
    for name, number in perGlyph:
        print(str(number).rjust(5), '|', name)
    print('Replaced references to "{oldName}" with "{newName}"'.format(
        oldName=oldName, newName=newName))
    print('Changed:', len(perGlyph), 'glyphs')
    print('Total:', total, 'references replaced')

    if total != 0:
        font.save()
def main_blockers(fontLocation, featureFileList):
    font = fontforge.open(fontLocation)
    featureFiles = {name: readLines(name) for name in featureFileList}

    marked = getMarkedGlyphs(font)
    dependents = getDependents(marked, font)
    table = sorted(
        [getTableRow(glyph, dependents, featureFiles) for glyph in marked],
        reverse=True)

    headers = [
        'unicode', 'is exception', '1-hard deps', 'n-hard deps', 'soft deps',
        'in fea', 'name'
    ]
    headerSizes = [len(name) for name in headers]
    print(' | '.join(headers))
    for row in table:
        # skip rows that would be removed by removeInaccessibleGlyphs.py
        if tuple(row[:-1]) == (False, False, 0, 0, 0, False): continue
        index = iter(xrange(len(headers)))
        print(' | '.join(
            [str(item).rjust(headerSizes[index.next()]) for item in row]))
Beispiel #24
0
def makeDesktop(infile, outfile, latinfile, feafile, version, generate=True):
    font = fontforge.open(infile)
    font.encoding = "UnicodeFull"  # avoid a crash if compact was set

    if version:
        setVersion(font, version)

    # remove anchors that are not needed in the production font
    cleanAnchors(font)

    mergeLatin(font, latinfile)
    #simpleFontMerge(font, latinfile)
    makeNumerators(font)

    # we want to merge features after merging the latin font because many
    # referenced glyphs are in the latin font
    prepareFeatures(font, feafile)

    if generate:
        generateFont(font, outfile)
    else:
        return font
Beispiel #25
0
def mergeLatin(font, feafile, italic=False, glyphs=None, quran=False):
    styles = {"Regular": "Roman", "Slanted": "Italic", "Bold": "Bold", "BoldSlanted": "BoldItalic"}

    style = styles[font.fontname.split("-")[1]]

    latinfile = "Crimson-%s.sfd" % style

    tmpfont = mkstemp(suffix=os.path.basename(latinfile))[1]
    latinfont = fontforge.open("sources/crimson/%s" % latinfile)

    validateGlyphs(latinfont)  # to flatten nested refs mainly

    if glyphs:
        latinglyphs = list(glyphs)
    else:
        # collect latin glyphs we want to keep
        latinglyphs = []

        # we want all glyphs in latin0-9 encodings
        for i in range(0, 9):
            latinfont.encoding = "latin%d" % i
            for glyph in latinfont.glyphs("encoding"):
                if glyph.encoding <= 255:
                    if glyph.glyphname not in latinglyphs:
                        latinglyphs.append(glyph.glyphname)
                elif glyph.unicode != -1 and glyph.unicode <= 0x017F:
                    # keep also Unicode Latin Extended-A block
                    if glyph.glyphname not in latinglyphs:
                        latinglyphs.append(glyph.glyphname)
                elif glyph.unicode == -1 and ".prop" in glyph.glyphname:
                    # proportional digits
                    latinglyphs.append(glyph.glyphname)

        # keep ligatures too
        ligatures = (
            "f_b",
            "f_f_b",
            "f_h",
            "f_f_h",
            "f_i",
            "f_f_i",
            "f_j",
            "f_f_j",
            "f_k",
            "f_f_k",
            "f_l",
            "f_f_l",
            "f_f",
        )

        # and Arabic romanisation characters
        romanisation = (
            "uni02BC",
            "uni02BE",
            "uni02BE",
            "amacron",
            "uni02BE",
            "amacron",
            "eacute",
            "uni1E6F",
            "ccedilla",
            "uni1E6F",
            "gcaron",
            "ycircumflex",
            "uni1E29",
            "uni1E25",
            "uni1E2B",
            "uni1E96",
            "uni1E0F",
            "dcroat",
            "scaron",
            "scedilla",
            "uni1E63",
            "uni1E11",
            "uni1E0D",
            "uni1E6D",
            "uni1E93",
            "dcroat",
            "uni02BB",
            "uni02BF",
            "rcaron",
            "grave",
            "gdotaccent",
            "gbreve",
            "umacron",
            "imacron",
            "amacron",
            "amacron",
            "uni02BE",
            "amacron",
            "uni02BE",
            "acircumflex",
            "amacron",
            "uni1E97",
            "tbar",
            "aacute",
            "amacron",
            "ygrave",
            "agrave",
            "uni02BE",
            "aacute",
            "Amacron",
            "Amacron",
            "Eacute",
            "uni1E6E",
            "Ccedilla",
            "uni1E6E",
            "Gcaron",
            "Ycircumflex",
            "uni1E28",
            "uni1E24",
            "uni1E2A",
            "uni1E0E",
            "Dcroat",
            "Scaron",
            "Scedilla",
            "uni1E62",
            "uni1E10",
            "uni1E0C",
            "uni1E6C",
            "uni1E92",
            "Dcroat",
            "Rcaron",
            "Gdotaccent",
            "Gbreve",
            "Umacron",
            "Imacron",
            "Amacron",
            "Amacron",
            "Amacron",
            "Acircumflex",
            "Amacron",
            "Tbar",
            "Aacute",
            "Amacron",
            "Ygrave",
            "Agrave",
            "Aacute",
        )

        # and some typographic characters
        typographic = (
            "uni2010",
            "uni2011",
            "figuredash",
            "endash",
            "emdash",
            "uni2015",
            "quoteleft",
            "quoteright",
            "quotesinglbase",
            "quotereversed",
            "quotedblleft",
            "quotedblright",
            "quotedblbase",
            "uni201F",
            "dagger",
            "daggerdbl",
            "bullet",
            "onedotenleader",
            "ellipsis",
            "uni202F",
            "perthousand",
            "minute",
            "second",
            "uni2038",
            "guilsinglleft",
            "guilsinglright",
            "uni203E",
            "fraction",
            "i.TRK",
            "minus",
            "uni2213",
            "radical",
            "uni2042",
        )

        for l in (ligatures, romanisation, typographic):
            for name in l:
                if name not in latinglyphs:
                    latinglyphs.append(name)

    if not quran:
        # we want our ring above and below in Quran font only
        for name in ("uni030A", "uni0325"):
            font[name].clear()

        latinglyphs += buildComposition(latinfont, latinglyphs)
    subsetFont(latinfont, latinglyphs)

    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine")

    # common characters that can be used in Arabic and Latin need to be handled
    # carefully in the slanted font so that right leaning italic is used with
    # Latin, and left leaning slanted is used with Arabic, using ltra and rtla
    # features respectively, for less OpenType savvy apps we make the default
    # upright so it works reasonably with bot scripts
    if italic:
        if "Bold" in style:
            upright = fontforge.open("sources/crimson/Crimson-Bold.sfd")
        else:
            upright = fontforge.open("sources/crimson/Crimson-Roman.sfd")

        shared = (
            "exclam",
            "quotedbl",
            "numbersign",
            "dollar",
            "percent",
            "quotesingle",
            "asterisk",
            "plus",
            "colon",
            "semicolon",
            "less",
            "equal",
            "greater",
            "question",
            "at",
            "asciicircum",
            "exclamdown",
            "section",
            "copyright",
            "logicalnot",
            "registered",
            "plusminus",
            "uni00B2",
            "uni00B3",
            "paragraph",
            "uni00B9",
            "ordmasculine",
            "onequarter",
            "onehalf",
            "threequarters",
            "questiondown",
            "quoteleft",
            "quoteright",
            "quotesinglbase",
            "quotereversed",
            "quotedblleft",
            "quotedblright",
            "quotedblbase",
            "uni201F",
            "dagger",
            "daggerdbl",
            "perthousand",
            "minute",
            "second",
            "guilsinglleft",
            "guilsinglright",
            "fraction",
            "uni2213",
        )

        for name in shared:
            glyph = latinfont[name]
            glyph.clear()
            upright.selection.select(name)
            upright.copy()
            latinfont.createChar(upright[name].encoding, name)
            latinfont.selection.select(name)
            latinfont.paste()

        for name in digits:
            glyph = latinfont[name]
            glyph.glyphname += ".ltr"
            glyph.unicode = -1
            upright.selection.select(name)
            upright.copy()
            latinfont.createChar(upright[name].encoding, name)
            latinfont.selection.select(name)
            latinfont.paste()

            rtl = latinfont.createChar(-1, name + ".rtl")
            rtl.addReference(name, italic)
            rtl.useRefsMetrics(name)

        for name in digits:
            pname = name + ".prop"
            upright.selection.select(pname)
            upright.copy()
            latinfont.createChar(-1, pname)
            latinfont.selection.select(pname)
            latinfont.paste()

        for name in digits:
            pname = name + ".prop"
            rtl = latinfont.createChar(-1, name + ".rtl" + ".prop")
            rtl.addReference(pname, italic)
            rtl.useRefsMetrics(pname)

    # copy kerning classes
    kern_lookups = {}
    if not quran:
        for lookup in latinfont.gpos_lookups:
            kern_lookups[lookup] = {}
            kern_lookups[lookup]["subtables"] = []
            kern_lookups[lookup]["type"], kern_lookups[lookup]["flags"] = latinfont.getLookupInfo(lookup)[:2]
            for subtable in latinfont.getLookupSubtables(lookup):
                if latinfont.isKerningClass(subtable):
                    kern_lookups[lookup]["subtables"].append((subtable, latinfont.getKerningClass(subtable)))

    for lookup in latinfont.gpos_lookups:
        latinfont.removeLookup(lookup)

    for lookup in latinfont.gsub_lookups:
        latinfont.removeLookup(lookup)

    latinfont.save(tmpfont)
    latinfont.close()

    font.mergeFonts(tmpfont)
    os.remove(tmpfont)

    if not quran:
        buildComposition(font, latinglyphs)

    # add Latin small and medium digits
    for name in digits:
        if italic:
            # they are only used in Arabic contexts, so always reference the
            # italic rtl variant
            refname = name + ".rtl"
        else:
            refname = name
        small = font.createChar(-1, name + ".small")
        small.clear()
        small.addReference(refname, psMat.scale(0.6))
        small.transform(psMat.translate(0, -40))
        small.width = 600
        centerGlyph(small)

        medium = font.createChar(-1, name + ".medium")
        medium.clear()
        medium.addReference(refname, psMat.scale(0.8))
        medium.transform(psMat.translate(0, 50))
        medium.width = 900
        centerGlyph(medium)

    for lookup in kern_lookups:
        font.addLookup(lookup, kern_lookups[lookup]["type"], kern_lookups[lookup]["flags"], (("kern", script_lang),))

        for subtable in kern_lookups[lookup]["subtables"]:
            first = []
            second = []
            offsets = subtable[1][2]

            # drop non-existing glyphs
            for new_klasses, klasses in ((first, subtable[1][0]), (second, subtable[1][1])):
                for klass in klasses:
                    new_klass = []
                    if klass:
                        for name in klass:
                            if name in font:
                                new_klass.append(name)
                    new_klasses.append(new_klass)

            # if either of the classes is empty, don’t bother with the subtable
            if any(first) and any(second):
                font.addKerningClass(lookup, subtable[0], first, second, offsets)
Beispiel #26
0
except ImportError:
    print >> sys.stderr, "Failed to import sortsmill, failing back to fontforge"
    import fontforge
import argparse
from datetime import date
from os import path

parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input", required=True)
parser.add_argument("-o", "--output", required=True)
parser.add_argument("-v", "--version", required=True)
parser.add_argument("-f", "--feature-file", required=False)

args = parser.parse_args()

font = fontforge.open(args.input)

if args.feature_file and path.isfile(args.feature_file):
    font.mergeFeature(args.feature_file)

font.version = args.version
font.copyright = "Copyright 2003-2012 by Philipp H. Poll. Copyright 2012-%s Khaled Hosny." % date.today().year

font.appendSFNTName("English (US)", "Manufacturer", "Khaled Hosny")
font.appendSFNTName("English (US)", "Vendor URL", "https://github.com/khaledhosny/libertinus")
font.appendSFNTName("English (US)", "License URL", "http://scripts.sil.org/OFL")
font.appendSFNTName("English (US)", "License", '\
This Font Software is licensed under the SIL Open Font License, Version 1.1. \
This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR \
CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License \
for the specific language, permissions and limitations governing your use of \
Beispiel #27
0
def makeWeb(infile, outfile):
    """If we are building a web version then try to minimise file size"""

    # "short-post" generates a post table without glyph names to save some KBs
    # since glyph names are only needed for PDF's as readers use them to
    # "guess" characters when copying text, which is of little use in web fonts.
    flags = ("opentype", "short-post", "omit-instructions")

    fontforge.setPrefs("PreserveTables", "COLR,CPAL")

    font = fontforge.open(infile)
    font.encoding = "UnicodeBmp" # avoid a crash if compact was set

    # removed compatibility glyphs that of little use on the web
    compat_ranges = (
            (0xfb50, 0xfbb1),
            (0xfbd3, 0xfd3d),
            (0xfd50, 0xfdf9),
            (0xfdfc, 0xfdfc),
            (0xfe70, 0xfefc),
            )

    for glyph in font.glyphs():
        for i in compat_ranges:
            start = i[0]
            end = i[1]
            if start <= glyph.unicode <= end:
                font.removeGlyph(glyph)
                break

    tmpfile = mkstemp(suffix=os.path.basename(outfile))[1]
    font.generate(tmpfile, flags=flags)
    font.close()

    # now open in fontTools
    from fontTools.ttLib import TTFont
    ftfont = TTFont(tmpfile)

    # our 'name' table is a bit bulky, and of almost no use in for web fonts,
    # so we strip all unnecessary entries.
    name = ftfont['name']
    names = []
    for record in name.names:
        platID = record.platformID
        langID = record.langID
        nameID = record.nameID

        # we keep only en_US entries in Windows and Mac platform id, every
        # thing else is dropped
        if (platID == 1 and langID == 0) or (platID == 3 and langID == 1033):
            if nameID == 13:
                # the full OFL text is too much, replace it with a simple
                # string
                if platID == 3:
                    # MS strings are UTF-16 encoded
                    text = 'OFL v1.1'.encode('utf_16_be')
                else:
                    text = 'OFL v1.1'
                record.string = text
                names.append(record)
            # keep every thing else except Descriptor, Sample Text
            elif nameID not in (10, 19):
                names.append(record)

    name.names = names

    # force compiling tables by fontTools, saves few tens of KBs
    for tag in ftfont.keys():
        if hasattr(ftfont[tag], "compile"):
            ftfont[tag].compile(ftfont)

    ftfont.save(outfile)
    ftfont.close()

    os.remove(tmpfile)
Beispiel #28
0
            if len(g.references) != 0:
                g.references = follow_references(g)

        f.generate(temp_ttf.name, flags = flags)
        print('Compiling Graphite: ' + gdl_file + ' ' + temp_ttf.name + ' -> ' + ttf_file)
        compile_graphite(gdl_file, temp_ttf.name, ttf_file)
        temp_ttf.close()
    else:
        print('Generating ' + ttf_file)
        f.generate(ttf_file, flags = flags)

    print('Validating ' + ttf_file)
    subprocess.call(['sortsmill-lint', ttf_file])
    

#--------------------------------------------------------------------------

# If someone runs some script by using "fontforge -script", then name
# may be "__main__" and fontforge won't have a user interface, but
# also the |sys| module will not yet have an |argv| attribute. Weed
# out that case.  Perhaps fontforge should handle the situation
# better. (5 Nov 2009)
if __name__ == '__main__' and not fontforge.hasUserInterface() and hasattr(sys, 'argv'):

    for font_file in sys.argv[1:]:
        f = fontforge.open(font_file)
        generate_tt_font(f, name_modifier)
        f.close()

#--------------------------------------------------------------------------
    p.wait();
    git_revison = p.stdout.read();
    fontlog = '\n'.join((
            datetime.datetime.now().isoformat(' ')
          , 'This file was generated from the sources of Amiri Font by Khaled Hosny,'
          , 'to serve as a blueprint for the font engineering of Jomhuria font.'
          , 'http://www.amirifont.org/'
          , 'Amiri git:  {amiriGit}'
          , 'git revison: {git_revison}'

        )).format(amiriGit=amiriGit, git_revison=git_revison)
    # just hijack what Khaled wrote, to make a subsetted, clean latin font
    import imp
    build = imp.load_source('build', os.path.join(amiriDir, 'tools', 'build.py'))

    amiriFont = fontforge.open(os.path.join(amiriDir, 'sources', 'amiri-regular.sfdir'))

    newFont = fontforge.font();
    # < needed for build.mergeLatin, it looks for the -Regular"
    newFont.fontname = 'JomhuriaLatin-Regular';
    # take the dimensions from amiri
    newFont.ascent = amiriFont.ascent
    newFont.descent = amiriFont.descent
    newFont.em = amiriFont.em
    newFont.fontlog = fontlog;

    # the source is quadratic, I want to keep that information in the background
    # the foreground will be cubic
    newFont.layers['Fore'].is_quadratic = True;
    newFont.layers['Back'].is_quadratic = True;
Beispiel #30
0
def copyAnchors(sourceFont, targetFont):
    count = 0
    for name in sourceFont:
        if name not in targetFont:
            continue
	glyph = targetFont[name]
        sourceAnchors = sourceFont[name].anchorPoints
        targetAnchors = {p[0]:p for p in glyph.anchorPoints}
	
        for p in sourceAnchors:
            if p[0] in targetAnchors: continue
            print glyph, 'adding', p
            glyph.addAnchorPoint(*p)
            count += 1
    return count


if __name__ == '__main__':
   # cd ./.build
    pairs = (
        ('amiri-font/sources/amiri-regular.sfdir', 'sources/jomhuria.sfdir')
      , ('amiri-font/sources/latin/amirilatin-regular.sfdir', 'sources/jomhuria-latin.sfdir')
    )
    for source, target in pairs:
        sourceFont = fontforge.open(source)
        targetFont = fontforge.open(target)
        if copyAnchors(sourceFont, targetFont):
            targetFont.save()


Beispiel #31
0
except ImportError:
    print >> sys.stderr, "Failed to import sortsmill, failing back to fontforge"
    import fontforge
import argparse
from datetime import date
from os import path

parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input", required=True)
parser.add_argument("-o", "--output", required=True)
parser.add_argument("-v", "--version", required=True)
parser.add_argument("-f", "--feature-file", required=False)

args = parser.parse_args()

font = fontforge.open(args.input)

if args.feature_file and path.isfile(args.feature_file):
    font.mergeFeature(args.feature_file)

font.version = args.version
font.copyright = u"Copyright © 2012-%s The Libertinus Project Authors." % date.today(
).year

font.appendSFNTName("English (US)", "Manufacturer", "Khaled Hosny")
font.appendSFNTName("English (US)", "Vendor URL",
                    "https://github.com/khaledhosny/libertinus")
font.appendSFNTName("English (US)", "License URL",
                    "http://scripts.sil.org/OFL")
font.appendSFNTName(
    "English (US)", "License",
Beispiel #32
0
def mergeLatin(font, latinfile, glyphs=None):
    tmpfont = mkstemp(
        suffix=os.path.basename(latinfile).replace("ufo", "sfd"))[1]
    latinfont = fontforge.open(latinfile)

    validateGlyphs(latinfont)  # to flatten nested refs mainly
    latinglyphs = [name for name in latinfont]

    # The Latin font is already subsetted to only contain glyphs that take
    # precedence over glyphs in the Arabic if there are overlapping glyphs.
    # To give the glyphs of the latin precedence, we need to remove the
    # existing glyphs from the Arabic.
    overlapping = {name for name in font} & {name for name in latinfont}
    for name in overlapping:
        # Maybe font.removeGlyph(name) is the better strategy than font[name].clear()
        # As it seems that the newly merged glyphs don't set all properties
        # of the glyph new on font.mergeFonts(latin)
        # If there are no references, removeGlyph should be better (there
        # were none when writing this)
        font.removeGlyph(name)

    compositions = buildComposition(latinfont, latinglyphs)
    latinglyphs += compositions
    subsetFont(latinfont, latinglyphs)

    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven",
              "eight", "nine")

    # copy kerning classes
    kern_lookups = {}
    for lookup in latinfont.gpos_lookups:
        kern_lookups[lookup] = {}
        kern_lookups[lookup]["subtables"] = []
        kern_lookups[lookup]["type"], kern_lookups[lookup][
            "flags"] = latinfont.getLookupInfo(lookup)[:2]
        for subtable in latinfont.getLookupSubtables(lookup):
            if latinfont.isKerningClass(subtable):
                kern_lookups[lookup]["subtables"].append(
                    (subtable, latinfont.getKerningClass(subtable)))

    for lookup in latinfont.gpos_lookups:
        latinfont.removeLookup(lookup)

    for lookup in latinfont.gsub_lookups:
        latinfont.removeLookup(lookup)

    latinfont.save(tmpfont)
    latinfont.close()

    font.mergeFonts(tmpfont)
    os.remove(tmpfont)

    copyAnchors(font, latinfile)

    buildComposition(font, latinglyphs)

    # add Latin small and medium digits
    for name in digits:
        refname = name
        small = font.createChar(-1, name + ".small")
        #if not small.isWorthOutputting():
        small.clear()
        small.addReference(refname, psMat.scale(0.6))
        small.transform(psMat.translate(0, 180))
        small.width = 650
        centerGlyph(small)

        medium = font.createChar(-1, name + ".medium")
        #if not medium.isWorthOutputting():
        medium.clear()
        medium.addReference(refname, psMat.scale(0.8))
        medium.transform(psMat.translate(0, 200))
        medium.width = 900
        centerGlyph(medium)

    for lookup in kern_lookups:
        font.addLookup(lookup, kern_lookups[lookup]["type"],
                       kern_lookups[lookup]["flags"],
                       (('kern', script_lang), ))

        for subtable in kern_lookups[lookup]["subtables"]:
            first = []
            second = []
            offsets = subtable[1][2]

            # drop non-existing glyphs
            for new_klasses, klasses in ((first, subtable[1][0]),
                                         (second, subtable[1][1])):
                for klass in klasses:
                    new_klass = []
                    if klass:
                        for name in klass:
                            if name in font:
                                new_klass.append(name)
                    new_klasses.append(new_klass)

            # if either of the classes is empty, don’t bother with the subtable
            if any(first) and any(second):
                font.addKerningClass(lookup, subtable[0], first, second,
                                     offsets)
Beispiel #33
0
def mergeLatin(font, feafile, italic=False, glyphs=None, quran=False):
    styles = {
        "Regular": "regular",
        "Slanted": "italic",
        "Bold": "bold",
        "BoldSlanted": "bolditalic"
    }

    style = styles[font.fontname.split("-")[1]]

    latinfile = "amirilatin-%s.sfdir" % style

    from tempfile import mkstemp
    tmpfont = mkstemp(
        suffix=os.path.basename(latinfile).replace("sfdir", "sfd"))[1]
    latinfont = fontforge.open("sources/latin/%s" % latinfile)

    validateGlyphs(latinfont)  # to flatten nested refs mainly

    if glyphs:
        latinglyphs = list(glyphs)
    else:
        # collect latin glyphs we want to keep
        latinglyphs = []

        # we want all glyphs in latin0-9 encodings
        for i in range(0, 9):
            latinfont.encoding = 'latin%d' % i
            for glyph in latinfont.glyphs("encoding"):
                if glyph.encoding <= 255:
                    if glyph.glyphname not in latinglyphs:
                        latinglyphs.append(glyph.glyphname)
                elif glyph.unicode != -1 and glyph.unicode <= 0x017F:
                    # keep also Unicode Latin Extended-A block
                    if glyph.glyphname not in latinglyphs:
                        latinglyphs.append(glyph.glyphname)
                elif glyph.unicode == -1 and '.prop' in glyph.glyphname:
                    # proportional digits
                    latinglyphs.append(glyph.glyphname)

        # keep ligatures too
        ligatures = ("f_b", "f_f_b", "f_h", "f_f_h", "f_i", "f_f_i", "f_j",
                     "f_f_j", "f_k", "f_f_k", "f_l", "f_f_l", "f_f")

        # and Arabic romanisation characters
        romanisation = ("uni02BC", "uni02BE", "uni02BE", "amacron", "uni02BE",
                        "amacron", "eacute", "uni1E6F", "ccedilla", "uni1E6F",
                        "gcaron", "ycircumflex", "uni1E29", "uni1E25",
                        "uni1E2B", "uni1E96", "uni1E0F", "dcroat", "scaron",
                        "scedilla", "uni1E63", "uni1E11", "uni1E0D", "uni1E6D",
                        "uni1E93", "dcroat", "uni02BB", "uni02BF", "rcaron",
                        "grave", "gdotaccent", "gbreve", "umacron", "imacron",
                        "amacron", "amacron", "uni02BE", "amacron", "uni02BE",
                        "acircumflex", "amacron", "uni1E97", "tbar", "aacute",
                        "amacron", "ygrave", "agrave", "uni02BE", "aacute",
                        "Amacron", "Amacron", "Eacute", "uni1E6E", "Ccedilla",
                        "uni1E6E", "Gcaron", "Ycircumflex", "uni1E28",
                        "uni1E24", "uni1E2A", "uni1E0E", "Dcroat", "Scaron",
                        "Scedilla", "uni1E62", "uni1E10", "uni1E0C", "uni1E6C",
                        "uni1E92", "Dcroat", "Rcaron", "Gdotaccent", "Gbreve",
                        "Umacron", "Imacron", "Amacron", "Amacron", "Amacron",
                        "Acircumflex", "Amacron", "Tbar", "Aacute", "Amacron",
                        "Ygrave", "Agrave", "Aacute")

        # and some typographic characters
        typographic = ("uni2010", "uni2011", "figuredash", "endash", "emdash",
                       "uni2015", "quoteleft", "quoteright", "quotesinglbase",
                       "quotereversed", "quotedblleft", "quotedblright",
                       "quotedblbase", "uni201F", "dagger", "daggerdbl",
                       "bullet", "onedotenleader", "ellipsis", "uni202F",
                       "perthousand", "minute", "second", "uni2038",
                       "guilsinglleft", "guilsinglright", "uni203E",
                       "fraction", "i.TRK", "minus", "uni2213", "radical",
                       "uni2042")

        for l in (ligatures, romanisation, typographic):
            for name in l:
                if name not in latinglyphs:
                    latinglyphs.append(name)

    if not quran:
        # we want our ring above and below in Quran font only
        for name in ("uni030A", "uni0325"):
            font[name].clear()

        latinglyphs += buildComposition(latinfont, latinglyphs)
    subsetFont(latinfont, latinglyphs)

    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven",
              "eight", "nine")

    # common characters that can be used in Arabic and Latin need to be handled
    # carefully in the slanted font so that right leaning italic is used with
    # Latin, and left leaning slanted is used with Arabic, using ltra and rtla
    # features respectively, for less OpenType savvy apps we make the default
    # upright so it works reasonably with bot scripts
    if italic:
        if "bold" in style:
            upright = fontforge.open("sources/latin/amirilatin-bold.sfdir")
        else:
            upright = fontforge.open("sources/latin/amirilatin-regular.sfdir")

        shared = ("exclam", "quotedbl", "numbersign", "dollar", "percent",
                  "quotesingle", "asterisk", "plus", "colon", "semicolon",
                  "less", "equal", "greater", "question", "at", "asciicircum",
                  "exclamdown", "section", "copyright", "logicalnot",
                  "registered", "plusminus", "uni00B2", "uni00B3", "paragraph",
                  "uni00B9", "ordmasculine", "onequarter", "onehalf",
                  "threequarters", "questiondown", "quoteleft", "quoteright",
                  "quotesinglbase", "quotereversed", "quotedblleft",
                  "quotedblright", "quotedblbase", "uni201F", "dagger",
                  "daggerdbl", "perthousand", "minute", "second",
                  "guilsinglleft", "guilsinglright", "fraction", "uni2213")

        for name in shared:
            glyph = latinfont[name]
            glyph.clear()
            upright.selection.select(name)
            upright.copy()
            latinfont.createChar(upright[name].encoding, name)
            latinfont.selection.select(name)
            latinfont.paste()

        for name in digits:
            glyph = latinfont[name]
            glyph.glyphname += '.ltr'
            glyph.unicode = -1
            upright.selection.select(name)
            upright.copy()
            latinfont.createChar(upright[name].encoding, name)
            latinfont.selection.select(name)
            latinfont.paste()

            rtl = latinfont.createChar(-1, name + ".rtl")
            rtl.addReference(name, italic)
            rtl.useRefsMetrics(name)

        for name in digits:
            pname = name + ".prop"
            glyph = latinfont[pname]
            glyph.glyphname = name + '.ltr.prop'
            glyph.unicode = -1
            upright.selection.select(pname)
            upright.copy()
            latinfont.createChar(-1, pname)
            latinfont.selection.select(pname)
            latinfont.paste()

            rtl = latinfont.createChar(-1, name + ".rtl" + ".prop")
            rtl.addReference(pname, italic)
            rtl.useRefsMetrics(pname)

    # copy kerning classes
    kern_lookups = {}
    if not quran:
        for lookup in latinfont.gpos_lookups:
            kern_lookups[lookup] = {}
            kern_lookups[lookup]["subtables"] = []
            kern_lookups[lookup]["type"], kern_lookups[lookup][
                "flags"] = latinfont.getLookupInfo(lookup)[:2]
            for subtable in latinfont.getLookupSubtables(lookup):
                if latinfont.isKerningClass(subtable):
                    kern_lookups[lookup]["subtables"].append(
                        (subtable, latinfont.getKerningClass(subtable)))

    for lookup in latinfont.gpos_lookups:
        latinfont.removeLookup(lookup)

    for lookup in latinfont.gsub_lookups:
        latinfont.removeLookup(lookup)

    latinfont.save(tmpfont)
    latinfont.close()

    font.mergeFonts(tmpfont)
    os.remove(tmpfont)

    if not quran:
        buildComposition(font, latinglyphs)

    # add Latin small and medium digits
    for name in digits:
        if italic:
            # they are only used in Arabic contexts, so always reference the
            # italic rtl variant
            refname = name + ".rtl"
        else:
            refname = name
        small = font.createChar(-1, name + ".small")
        if not small.isWorthOutputting():
            small.clear()
            small.addReference(refname, psMat.scale(0.6))
            small.transform(psMat.translate(0, -40))
            small.width = 600
            centerGlyph(small)

        medium = font.createChar(-1, name + ".medium")
        if not medium.isWorthOutputting():
            medium.clear()
            medium.addReference(refname, psMat.scale(0.8))
            medium.transform(psMat.translate(0, 50))
            medium.width = 900
            centerGlyph(medium)

    for lookup in kern_lookups:
        font.addLookup(lookup, kern_lookups[lookup]["type"],
                       kern_lookups[lookup]["flags"],
                       (('kern', script_lang), ))

        for subtable in kern_lookups[lookup]["subtables"]:
            first = []
            second = []
            offsets = subtable[1][2]

            # drop non-existing glyphs
            for new_klasses, klasses in ((first, subtable[1][0]),
                                         (second, subtable[1][1])):
                for klass in klasses:
                    new_klass = []
                    if klass:
                        for name in klass:
                            if name in font:
                                new_klass.append(name)
                    new_klasses.append(new_klass)

            # if either of the classes is empty, don’t bother with the subtable
            if any(first) and any(second):
                font.addKerningClass(lookup, subtable[0], first, second,
                                     offsets)
Beispiel #34
0
def merge(args):
    arabic = fontforge.open(args.arabicfile)
    arabic.encoding = "Unicode"
    arabic.mergeFeature(args.feature_file)

    latin = fontforge.open(args.latinfile)
    latin.encoding = "Unicode"
    latin.em = arabic.em

    latin_locl = ""
    for glyph in latin.glyphs():
        if glyph.color == 0xff0000:
            latin.removeGlyph(glyph)
        else:
            if glyph.glyphname in arabic:
                name = glyph.glyphname
                glyph.unicode = -1
                glyph.glyphname = name + ".latin"
                if not latin_locl:
                    latin_locl = "feature locl {lookupflag IgnoreMarks; script latn;"
                latin_locl += "sub %s by %s;" % (name, glyph.glyphname)

    arabic.mergeFonts(latin)
    if latin_locl:
        latin_locl += "} locl;"
        arabic.mergeFeatureString(latin_locl)

    for ch in [(ord(u'،'), "comma"), (ord(u'؛'), "semicolon")]:
        ar = arabic.createChar(ch[0], fontforge.nameFromUnicode(ch[0]))
        en = arabic[ch[1]]
        colon = arabic["colon"]
        ar.addReference(en.glyphname, psMat.rotate(math.radians(180)))
        delta = colon.boundingBox()[1] - ar.boundingBox()[1]
        ar.transform(psMat.translate(0, delta))
        ar.left_side_bearing = en.right_side_bearing
        ar.right_side_bearing = en.left_side_bearing

    question_ar = arabic.createChar(ord(u'؟'), "uni061F")
    question_ar.addReference("question", psMat.scale(-1, 1))
    question_ar.left_side_bearing = arabic["question"].right_side_bearing
    question_ar.right_side_bearing = arabic["question"].left_side_bearing

    # Set metadata
    arabic.version = args.version
    years = datetime.now().year == 2015 and 2015 or "2015-%s" % datetime.now().year

    arabic.copyright = ". ".join(["Portions copyright © %s, Khaled Hosny (<*****@*****.**>)",
                              "Portions " + latin.copyright[0].lower() + latin.copyright[1:].replace("(c)", "©")])
    arabic.copyright = arabic.copyright % years

    handle_cloned_glyphs(arabic)

    en = "English (US)"
    arabic.appendSFNTName(en, "Designer", "Khaled Hosny")
    arabic.appendSFNTName(en, "License URL", "http://scripts.sil.org/OFL")
    arabic.appendSFNTName(en, "License", 'This Font Software is licensed under the SIL Open Font License, Version 1.1. \
This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR \
CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License \
for the specific language, permissions and limitations governing your use of \
this Font Software.')
    arabic.appendSFNTName(en, "Descriptor", "Mada is a geometric, unmodulted Arabic display typeface inspired by Cairo road signage.")
    arabic.appendSFNTName(en, "Sample Text", "صف خلق خود كمثل ٱلشمس إذ بزغت يحظى ٱلضجيع بها نجلاء معطار.")

    return arabic
Beispiel #35
0
def makeWeb(infile, outfile):
    """If we are building a web version then try to minimise file size"""

    # "short-post" generates a post table without glyph names to save some KBs
    # since glyph names are only needed for PDF's as readers use them to
    # "guess" characters when copying text, which is of little use in web fonts.
    flags = ("opentype", "short-post", "omit-instructions")

    font = fontforge.open(infile)
    font.encoding = "UnicodeBmp"  # avoid a crash if compact was set

    # removed compatibility glyphs that of little use on the web
    compat_ranges = ((0xFB50, 0xFBB1), (0xFBD3, 0xFD3D), (0xFD50, 0xFDF9), (0xFDFC, 0xFDFC), (0xFE70, 0xFEFC))

    for glyph in font.glyphs():
        for i in compat_ranges:
            start = i[0]
            end = i[1]
            if start <= glyph.unicode <= end:
                font.removeGlyph(glyph)
                break

    tmpfont = mkstemp(suffix=os.path.basename(outfile))[1]
    font.generate(tmpfont, flags=flags)
    font.close()

    # now open in fontTools
    from fontTools.ttLib import TTFont

    font = TTFont(tmpfont, recalcBBoxes=0)

    # our 'name' table is a bit bulky, and of almost no use in for web fonts,
    # so we strip all unnecessary entries.
    name = font["name"]
    names = []
    for record in name.names:
        platID = record.platformID
        langID = record.langID
        nameID = record.nameID

        # we keep only en_US entries in Windows and Mac platform id, every
        # thing else is dropped
        if (platID == 1 and langID == 0) or (platID == 3 and langID == 1033):
            if nameID == 13:
                # the full OFL text is too much, replace it with a simple
                # string
                if platID == 3:
                    # MS strings are UTF-16 encoded
                    text = "OFL v1.1".encode("utf_16_be")
                else:
                    text = "OFL v1.1"
                record.string = text
                names.append(record)
            # keep every thing else except Descriptor, Sample Text
            elif nameID not in (10, 19):
                names.append(record)

    name.names = names

    # FFTM is FontForge specific, remove it
    del (font["FFTM"])

    # force compiling GPOS/GSUB tables by fontTools, saves few tens of KBs
    for tag in ("GPOS", "GSUB"):
        font[tag].compile(font)

    font.save(outfile)
    font.close()

    os.remove(tmpfont)
import sys
from sortsmill import ffcompat as fontforge

amiri = fontforge.open(sys.argv[1])
xits = fontforge.open(sys.argv[2])

amiri.em = 1000
amiri.layers[1].is_quadratic = 0
amiri.selection.all()
amiri.unlinkReferences()

names = []
alts = []
for aglyph in amiri.glyphs():
    u = aglyph.unicode
    if (u in range(0x1EE00, 0x1EF00) or u in range(0x0660, 0x066E)
            or u in range(0x06F0, 0x06FA) or u in range(0x0608, 0x060B)):
        names.append(aglyph.name)

for aglyph in amiri.glyphs():
    for name in names:
        if aglyph.name != name and aglyph.name.startswith(name + ".alt"):
            alts.append(aglyph.name)

for name in names + alts:
    aglyph = amiri[name]
    if aglyph.name not in xits:
        xits.createChar(aglyph.unicode, aglyph.name)
    xglyph = xits[aglyph.name]
    aglyph.draw(xglyph.glyphPen())
    xglyph.width = aglyph.width
Beispiel #37
0
from sortsmill import ffcompat as fontforge
import sys

font = fontforge.open(sys.argv[1])

if len(sys.argv) > 4:
  font.mergeFeature(sys.argv[4])

font.version = sys.argv[3]
# no need for this on the web, saves few KBs
font.appendSFNTName ("English (US)", "Descriptor", "")
font.generate(sys.argv[2], flags=("round", "opentype", "short-post"))

Beispiel #38
0
def makeWeb(infile, outfile):
    """If we are building a web version then try to minimise file size"""

    # "short-post" generates a post table without glyph names to save some KBs
    # since glyph names are only needed for PDF's as readers use them to
    # "guess" characters when copying text, which is of little use in web fonts.
    flags = ("opentype", "short-post", "omit-instructions")

    font = fontforge.open(infile)
    font.encoding = "UnicodeBmp"  # avoid a crash if compact was set

    # removed compatibility glyphs that of little use on the web
    compat_ranges = (
        (0xfb50, 0xfbb1),
        (0xfbd3, 0xfd3d),
        (0xfd50, 0xfdf9),
        (0xfdfc, 0xfdfc),
        (0xfe70, 0xfefc),
    )

    for glyph in font.glyphs():
        for i in compat_ranges:
            start = i[0]
            end = i[1]
            if start <= glyph.unicode <= end:
                font.removeGlyph(glyph)
                break

    tmpfile = mkstemp(suffix=os.path.basename(outfile))[1]
    font.generate(tmpfile, flags=flags)
    font.close()

    # now open in fontTools
    from fontTools.ttLib import TTFont
    ftfont = TTFont(tmpfile)

    # our 'name' table is a bit bulky, and of almost no use in for web fonts,
    # so we strip all unnecessary entries.
    name = ftfont['name']
    names = []
    for record in name.names:
        platID = record.platformID
        langID = record.langID
        nameID = record.nameID

        # we keep only en_US entries in Windows and Mac platform id, every
        # thing else is dropped
        if (platID == 1 and langID == 0) or (platID == 3 and langID == 1033):
            if nameID == 13:
                # the full OFL text is too much, replace it with a simple
                # string
                if platID == 3:
                    # MS strings are UTF-16 encoded
                    text = 'OFL v1.1'.encode('utf_16_be')
                else:
                    text = 'OFL v1.1'
                record.string = text
                names.append(record)
            # keep every thing else except Descriptor, Sample Text
            elif nameID not in (10, 19):
                names.append(record)

    name.names = names

    # force compiling tables by fontTools, saves few tens of KBs
    for tag in ftfont.keys():
        if hasattr(ftfont[tag], "compile"):
            ftfont[tag].compile(ftfont)

    ftfont.save(outfile)
    ftfont.close()

    os.remove(tmpfile)