summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/fonts/amiri/tools/build.py
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2011-12-05 23:57:35 +0000
committerKarl Berry <karl@freefriends.org>2011-12-05 23:57:35 +0000
commitb498571214c4c006b799b67615b4dbcdb1d310f1 (patch)
treee31e327c4248c145010362917dc569a9756a176d /Master/texmf-dist/doc/fonts/amiri/tools/build.py
parente3d429df329fc5641edc1e127e76f8c195f8bbf0 (diff)
new font amiri (4dec11)
git-svn-id: svn://tug.org/texlive/trunk@24768 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/doc/fonts/amiri/tools/build.py')
-rwxr-xr-xMaster/texmf-dist/doc/fonts/amiri/tools/build.py324
1 files changed, 324 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/fonts/amiri/tools/build.py b/Master/texmf-dist/doc/fonts/amiri/tools/build.py
new file mode 100755
index 00000000000..c72eb81c706
--- /dev/null
+++ b/Master/texmf-dist/doc/fonts/amiri/tools/build.py
@@ -0,0 +1,324 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# build.py - Amiri font build utility
+#
+# Written in 2010-2011 by Khaled Hosny <khaledhosny@eglug.org>
+#
+# To the extent possible under law, the author have dedicated all copyright
+# and related and neighboring rights to this software to the public domain
+# worldwide. This software is distributed without any warranty.
+#
+# You should have received a copy of the CC0 Public Domain Dedication along
+# with this software. If not, see
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+import fontforge
+import sys
+import os
+import getopt
+import tempfile
+
+def genCSS(font, base):
+ style = ("slanted" in font.fullname.lower()) and "oblique" or "normal"
+ weight = font.os2_weight
+ family = font.familyname + "Web"
+
+ css = """
+@font-face {
+ font-family: %(family)s;
+ font-style: %(style)s;
+ font-weight: %(weight)s;
+ src: url('%(base)s.eot?') format('eot'),
+ url('%(base)s.woff') format('woff'),
+ url('%(base)s.ttf') format('truetype');
+}
+""" %{"style":style, "weight":weight, "family":family, "base":base}
+
+ return css
+
+def cleanAnchors(font):
+ klasses = (
+ "Dash",
+ "DigitAbove",
+ "DigitBelow",
+ "DotAbove",
+ "DotAlt",
+ "DotBelow",
+ "DotBelowAlt",
+ "DotHmaza",
+ "HighHamza",
+ "MarkDotAbove",
+ "MarkDotBelow",
+ "RingBelow",
+ "RingDash",
+ "Stroke",
+ "TaaAbove",
+ "TaaBelow",
+ "Tail",
+ "TashkilAboveDot",
+ "TashkilBelowDot",
+ "TwoDotsAbove",
+ "TwoDotsBelow",
+ "TwoDotsBelowAlt"
+ )
+
+ for klass in klasses:
+ subtable = font.getSubtableOfAnchor(klass)
+ lookup = font.getLookupOfSubtable(subtable)
+ font.removeLookup(lookup)
+
+def cleanUnused(font):
+ for glyph in font.glyphs():
+ # glyphs colored yellow are pending removal, so we remove them from the
+ # final font.
+ if glyph.color == 0xffff00:
+ font.removeGlyph(glyph)
+
+def validateGlyphs(font):
+ flipped_ref = 0x10
+ wrong_dir = 0x8
+ missing_extrema = 0x20
+ for glyph in font.glyphs():
+ state = glyph.validate(True)
+ if state & flipped_ref:
+ glyph.unlinkRef()
+ glyph.correctDirection()
+ if state & wrong_dir:
+ glyph.correctDirection()
+ if state & missing_extrema:
+ glyph.addExtrema("all")
+
+def setVersion(font, version):
+ font.version = "%07.3f" %float(version)
+ font.appendSFNTName("Arabic (Egypt)", "Version", "إصدارة %s" %font.version.replace(".", ","))
+
+def mergeFeatures(font, feafile):
+ oldfea = tempfile.mkstemp(suffix='.fea')[1]
+ font.generateFeatureFile(oldfea)
+
+ for lookup in font.gpos_lookups:
+ font.removeLookup(lookup)
+
+ font.mergeFeature(feafile)
+ font.mergeFeature(oldfea)
+ os.remove(oldfea)
+
+def stripLocalName(font):
+ for name in font.sfnt_names:
+ if name[0] != "English (US)" and name[1] in ("Family", "Fullname"):
+ font.appendSFNTName(name[0], name[1], None)
+
+def makeCss(infile, outfile):
+ text = ""
+
+ for f in infile.split():
+ base = os.path.splitext(os.path.basename(f))[0]
+ font = fontforge.open(f)
+ text += genCSS(font, base)
+ font.close()
+
+ out = open(outfile, "w")
+ out.write(text)
+ out.close()
+
+def generateFont(font, outfile, hack=False):
+ flags = ("opentype", "dummy-dsig", "round")
+
+ if hack:
+ # ff takes long to write the file, so generate to tmp file then rename
+ # it to keep fontview happy
+ import subprocess
+ tmpout = tempfile.mkstemp(dir=".", suffix=os.path.basename(outfile))[1]
+ font.generate(tmpout, flags=flags)
+ #os.rename(tmpout, outfile) # file monitor will not see this, why?
+ p = subprocess.Popen("cat %s > %s" %(tmpout, outfile), shell=True)
+ p.wait()
+ os.remove(tmpout)
+ else:
+ font.generate(outfile, flags=flags)
+ font.close()
+
+def makeWeb(infile, outfile):
+ """If we are building a web version then try to minimise file size"""
+ from fontTools.ttLib import TTFont
+
+ # suppress noisy DeprecationWarnings in fontTools
+ import warnings
+ warnings.filterwarnings("ignore",category=DeprecationWarning)
+
+ font = TTFont(infile, recalcBBoxes=0)
+
+ # internal glyph names are useless on the web, so force a format 3 post
+ # table
+ post = font['post']
+ post.formatType = 3.0
+ post.glyphOrder = None
+ del(post.extraNames)
+ del(post.mapping)
+
+ # '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
+
+ # dummy DSIG is useless here too
+ del(font['DSIG'])
+
+ # FFTM is FontForge specific, remove too
+ 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()
+
+def makeSlanted(infile, outfile, slant):
+ import psMat
+ import math
+
+ font = fontforge.open(infile)
+
+ # compute amout of skew, magic formula copied from fontforge sources
+ skew = psMat.skew(-slant * math.pi/180.0)
+
+ font.selection.all()
+ font.transform(skew)
+
+ # fix metadata
+ font.italicangle = slant
+ font.fontname = font.fontname.replace("Regular", "Slanted")
+ font.fullname += " Slanted"
+ font.appendSFNTName("Arabic (Egypt)", "SubFamily", "مائل")
+
+def makeSfd(infile, outfile, version):
+ font = fontforge.open(infile)
+ if version:
+ setVersion(font, version)
+ font.save(outfile)
+ font.close()
+
+def makeDesktop(infile, outfile, feafile, version, nolocalname):
+ font = fontforge.open(infile)
+
+ if version:
+ setVersion(font, version)
+
+ # remove anchors that are not needed in the production font
+ cleanAnchors(font)
+
+ # fix some common font issues
+ validateGlyphs(font)
+
+ # remove unused glyphs
+ cleanUnused(font)
+
+ if nolocalname:
+ stripLocalName(font)
+
+ if feafile:
+ mergeFeatures(font, feafile)
+
+ generateFont(font, outfile, True)
+
+def usage(code):
+ message = """Usage: %s OPTIONS...
+
+Options:
+ --input=FILE file name of input font
+ --output=FILE file name of output font
+ --version=VALUE set font version to VALUE
+ --feature-file=FILE optional feature file
+ --slant=VALUE autoslant
+ --css output is a CSS file
+ --sfd output is a SFD file
+ --web output is web version
+ --desktop output is desktop version
+ --no-localised-name strip out localised font name
+
+ -h, --help print this message and exit
+""" % os.path.basename(sys.argv[0])
+
+ print message
+ sys.exit(code)
+
+if __name__ == "__main__":
+ try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:],
+ "h",
+ ["help","input=","output=", "feature-file=", "version=", "slant=", "css", "web", "desktop", "sfd", "no-localised-name"])
+ except getopt.GetoptError, err:
+ print str(err)
+ usage(-1)
+
+ infile = None
+ outfile = None
+ feafile = None
+ version = None
+ slant = False
+ css = False
+ web = False
+ desktop = False
+ sfd = False
+ nolocalname = False
+
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ usage(0)
+ elif opt == "--input": infile = arg
+ elif opt == "--output": outfile = arg
+ elif opt == "--feature-file": feafile = arg
+ elif opt == "--version": version = arg
+ elif opt == "--slant": slant = float(arg)
+ elif opt == "--css": css = True
+ elif opt == "--web": web = True
+ elif opt == "--desktop": desktop = True
+ elif opt == "--sfd": sfd = True
+ elif opt == "--no-localised-name": nolocalname = True
+
+ if not infile:
+ print "No input file"
+ usage(-1)
+ if not outfile:
+ print "No output file"
+ usage(-1)
+
+ if css:
+ makeCss(infile, outfile)
+
+ if sfd:
+ makeSfd(infile, outfile, version)
+
+ if slant:
+ makeSlanted(infile, outfile, slant)
+
+ if web:
+ makeWeb(infile, outfile)
+
+ if desktop:
+ makeDesktop(infile, outfile, feafile, version, nolocalname)