diff options
author | Christian Robertson <robertsonc@google.com> | 2014-05-19 16:09:20 -0700 |
---|---|---|
committer | Christian Robertson <robertsonc@google.com> | 2014-05-19 16:09:20 -0700 |
commit | 7051939fa74b5f8f453be605f5dc3b4c23e1d1d9 (patch) | |
tree | 65cb31b34a64b2b07f9f6fd1bcb58d9a4945a92d /scripts/lib/fontbuild/Build.py |
Importing Roboto 2.0
Diffstat (limited to 'scripts/lib/fontbuild/Build.py')
-rwxr-xr-x | scripts/lib/fontbuild/Build.py | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py new file mode 100755 index 0000000..d10cc9d --- /dev/null +++ b/scripts/lib/fontbuild/Build.py @@ -0,0 +1,227 @@ +from FL import * +from fontbuild.mix import Mix,Master,narrowFLGlyph +from fontbuild.instanceNames import setNames +from fontbuild.italics import italicizeGlyph +from fontbuild.convertCurves import glyphCurvesToQuadratic +from fontbuild.mitreGlyph import mitreGlyph +from fontbuild.generateGlyph import generateGlyph +from fontTools.misc.transform import Transform +from fontbuild.kerning import generateFLKernClassesFromOTString +import ConfigParser +import os + + +class FontProject: + + def __init__(self, basefont, basedir, configfile, thinfont = None): + self.basefont = basefont + self.thinfont = thinfont + self.basedir = basedir + self.config = ConfigParser.RawConfigParser() + self.configfile = self.basedir+"/"+configfile + self.config.read(self.configfile) + + diacriticList = open(self.basedir + "/" + self.config.get("res","diacriticfile")).readlines() + self.diacriticList = [line.strip() for line in diacriticList if not line.startswith("#")] + self.ot_classes = open(self.basedir + "/" + self.config.get("res","ot_classesfile")).read() + self.ot_kerningclasses = open(self.basedir + "/" + self.config.get("res","ot_kerningclassesfile")).read() + self.ot_features = open(self.basedir + "/" + self.config.get("res","ot_featuresfile")).read() + + self.builddir = "out" + self.decompose = self.config.get("glyphs","decompose").split() + self.predecompose = self.config.get("glyphs","predecompose").split() + self.lessItalic = self.config.get("glyphs","lessitalic").split() + self.deleteList = self.config.get("glyphs","delete").split() + self.buildnumber = self.loadBuildNumber() + + + def loadBuildNumber(self): + versionFile = open(self.basedir + "/" + self.config.get("main","buildnumberfile"), "r+") + buildnumber = int(versionFile.read().strip()) + buildnumber = "%05d" %(int(buildnumber) + 1) + print "BuildNumber: %s" %(buildnumber) + versionFile.close() + return buildnumber + + def incrementBuildNumber(self): + if len(self.buildnumber) > 0: + versionFile = open(self.basedir + "/" + self.config.get("main","buildnumberfile"), "r+") + versionFile.seek(0) + versionFile.write(self.buildnumber) + versionFile.truncate() + versionFile.close() + else: + raise Exception("Empty build number") + + + def generateFont(self, mix, names, italic=False, swapSuffixes=None, stemWidth=185, kern=True): + + n = names.split("/") + log("---------------------\n%s %s\n----------------------" %(n[0],n[1])) + log(">> Mixing masters") + if isinstance( mix, Mix): + f = mix.generateFont(self.basefont) + else: + f = Font(mix) + fl.Add(f) + index = fl.ifont + fl.CallCommand(33239) # Sort glyphs by unicode + if italic == True: + log(">> Italicizing") + fl.UpdateFont(fl.ifont) + tweakAmmount = .085 + narrowAmmount = .93 + if names.find("Thin") != -1: + tweakAmmount = .05 + if names.find("Condensed") != -1: + narrowAmmount = .96 + i = 0 + for g in f.glyphs: + i += 1 + if i % 10 == 0: print g.name + + # if i < 24: + # continue + # if i > 86: + # for i,g in enumerate(fl.font.glyphs): + # fl.UpdateGlyph(i) + # # break + # assert False + + # print g.name + # if self.thinfont != None: + # narrowFLGlyph(g,self.thinfont.getGlyph(g.name),factor=narrowAmmount) + + if g.name != "eight" or g.name != "Q": + g.RemoveOverlap() + + # not sure why FontLab sometimes refuses, seems to work if called twice + + if (g.name in self.lessItalic): + italicizeGlyph(g, 9, stemWidth=stemWidth) + else: + italicizeGlyph(g, 10, stemWidth=stemWidth) + g.RemoveOverlap() + g.width += 10 + fl.UpdateGlyph(i-1) + + if swapSuffixes != None: + for swap in swapSuffixes: + swapList = [g.name for g in f.glyphs if g.name.endswith(swap)] + for gname in swapList: + print gname + swapGlyphs(f, gname.replace(swap,""), gname) + for gname in self.predecompose: + g = f[f.FindGlyph(gname)] + if g != None: + g.Decompose() + + log(">> Generating glyphs") + generateGlyphs(f, self.diacriticList) + log(">> Copying features") + f.ot_classes = self.ot_classes + copyFeatures(self.basefont,f) + fl.UpdateFont(index) + log(">> Decomposing") + for gname in self.decompose: + g = f[f.FindGlyph(gname)] + if g != None: + g.Decompose() + g.Decompose() + + setNames(f, n, foundry=self.config.get('main','foundry'), + version=self.config.get('main','version'), + build=self.buildnumber) + cleanCurves(f) + deleteGlyphs(f,self.deleteList) + if kern: + generateFLKernClassesFromOTString(f,self.ot_kerningclasses) + log(">> Generating font files") + directoryName = n[0].replace(" ","") + directoryPath = "%s/%s/%sTTF"%(self.basedir,self.builddir,directoryName) + if not os.path.exists(directoryPath): + os.makedirs(directoryPath) + ttfName = "%s/%s.ttf"%(directoryPath,f.font_name) + fl.GenerateFont(fl.ifont,ftTRUETYPE,ttfName) + f.modified = 0 + fl.Close(index) + +def transformGlyphMembers(g, m): + g.width = int(g.width * m.a) + g.Transform(m) + for a in g.anchors: + p = Point(a.p) + p.Transform(m) + a.p = p + for c in g.components: + # Assumes that components have also been individually transformed + p = Point(0,0) + d = Point(c.deltas[0]) + d.Transform(m) + p.Transform(m) + d1 = d - p + c.deltas[0].x = d1.x + c.deltas[0].y = d1.y + s = Point(c.scale) + s.Transform(m) + #c.scale = s + +def swapGlyphs(f,gName1,gName2): + try: + g1 = f.glyphs[f.FindGlyph(gName1)] + g2 = f.glyphs[f.FindGlyph(gName2)] + except IndexError: + log("swapGlyphs failed for %s %s"%(gName1, gName2)) + return + g3 = Glyph(g1) + + g1.Clear() + g1.Insert(g2) + g1.SetMetrics(g2.GetMetrics()) + + g2.Clear() + g2.Insert(g3) + g2.SetMetrics(g3.GetMetrics()) + +def log(msg): + print msg + +# def addOTFeatures(f): +# f.ot_classes = ot_classes + +def copyFeatures(f1, f2): + for ft in f1.features: + t = Feature(ft.tag, ft.value) + f2.features.append(t) + #f2.ot_classes = f1.ot_classes + f2.classes = [] + f2.classes = f1.classes + +def generateGlyphs(f, glyphNames): + log(">> Generating diacritics") + glyphnames = [gname for gname in glyphNames if not gname.startswith("#") and gname != ""] + + for glyphName in glyphNames: + generateGlyph(f, glyphName) + +def cleanCurves(f): + log(">> Removing overlaps") + for g in f.glyphs: + g.UnselectAll() + g.RemoveOverlap() + + log(">> Mitring sharp corners") + # for g in f.glyphs: + # mitreGlyph(g, 3., .7) + + log(">> Converting curves to quadratic") + # for g in f.glyphs: + # glyphCurvesToQuadratic(g) + +def deleteGlyphs(f,deleteList): + fl.Unselect() + for name in deleteList: + glyphIndex = f.FindGlyph(name) + if glyphIndex != -1: + del f.glyphs[glyphIndex] + fl.UpdateFont() |