|
| 1 | +from fontTools.ttLib import TTFont |
| 2 | +from fontTools.pens.basePen import decomposeQuadraticSegment |
| 3 | +from sys import argv |
| 4 | + |
| 5 | +charsToDump = "0123456789:.\u2212" |
| 6 | +charsToNarrow = ":." |
| 7 | +narrowFraction = 0.8 |
| 8 | +maximizeDigitBounds = True |
| 9 | +equalizeWidths = "0123456789" |
| 10 | +fontName = "Roboto-Regular.ttf" if len(argv) < 2 else argv[1] |
| 11 | +className = "SansDigitsColon" if len(argv) < 3 else argv[2] |
| 12 | + |
| 13 | +ttf = TTFont(fontName) |
| 14 | +glyphs = ttf.getGlyphSet() |
| 15 | +map = ttf.getBestCmap() |
| 16 | + |
| 17 | + |
| 18 | +def multiply(m1,m2): |
| 19 | + return tuple( tuple(sum(m1[i][j]*m2[j][k] for j in range(len(m1[0]))) for k in range(len(m2[0]))) for i in range(len(m1)) ) |
| 20 | + |
| 21 | +def apply2d(m1,v): |
| 22 | + if v is None: |
| 23 | + return None |
| 24 | + else: |
| 25 | + return ( m1[0][0]*v[0] + m1[0][1]*v[1] + m1[0][2], m1[1][0]*v[0] + m1[1][1]*v[1] + m1[1][2] ) |
| 26 | + |
| 27 | +class MyPen(object): |
| 28 | + def __init__(self, indent="", transformation=[[1,0,0],[0,-1,0],[0,0,1]]): |
| 29 | + self.transformation = transformation |
| 30 | + self.indent = indent |
| 31 | + def shiftList(self, points): |
| 32 | + return [apply2d(self.transformation,point) for point in points] |
| 33 | + def shift(self, point): |
| 34 | + return apply2d(self.transformation,point) |
| 35 | + def moveTo(self, point): |
| 36 | + print(self.indent+"path.moveTo(%gf,%gf);" % self.shift(point)) |
| 37 | +# def curveTo(self, *points): |
| 38 | +# print(self.indent+"curveTo", self.shift(*points)) |
| 39 | + def qCurveTo(self, *points): |
| 40 | + decomp = decomposeQuadraticSegment(points) |
| 41 | + for pair in decomp: |
| 42 | + shifted = self.shiftList(pair) |
| 43 | + print(self.indent+"path.quadTo(%gf,%gf,%gf,%gf);" % tuple(shifted[0]+shifted[1])) |
| 44 | + def lineTo(self, point): |
| 45 | + print(self.indent+"path.lineTo(%gf,%gf);" % self.shift(point)) |
| 46 | + def closePath(self): |
| 47 | + print(self.indent+"path.close();") |
| 48 | + def endPath(self): |
| 49 | + print(self.indent+"// endPath") |
| 50 | + def addComponent(self, glyphName, t): |
| 51 | + print(self.indent+"// addComponent", glyphName, t) |
| 52 | + glyphs[glyphName].draw(MyPen(indent=self.indent,transformation=multiply(self.transformation,[ [t[0],t[2],t[4]],[t[1],t[3],t[5]],[0,0,1] ]))) |
| 53 | + |
| 54 | +class PointListPen(object): |
| 55 | + def __init__(self, transformation=[[1,0,0],[0,-1,0],[0,0,1]], pointList=[]): |
| 56 | + self.transformation = transformation |
| 57 | + self.pointList = pointList |
| 58 | + def update(self, point): |
| 59 | + p = apply2d(self.transformation,point) |
| 60 | + self.pointList.append(p) |
| 61 | + def moveTo(self, point): |
| 62 | + self.update(point) |
| 63 | +# def curveTo(self, *points): |
| 64 | +# print(self.indent+"curveTo", self.shift(*points)) |
| 65 | + def qCurveTo(self, *points): |
| 66 | + decomp = decomposeQuadraticSegment(points) |
| 67 | + for pair in decomp: |
| 68 | + self.update(pair[1]) |
| 69 | + def lineTo(self, point): |
| 70 | + self.update(point) |
| 71 | + def closePath(self): |
| 72 | + pass |
| 73 | + def endPath(self): |
| 74 | + pass |
| 75 | + def addComponent(self, glyphName, t): |
| 76 | + glyphs[glyphName].draw(PointListPen(pointList=self.pointList, transformation=multiply(self.transformation,[ [t[0],t[2],t[4]],[t[1],t[3],t[5]],[0,0,1] ]))) |
| 77 | + |
| 78 | +plPen = PointListPen() |
| 79 | +glyphs["M"].draw(plPen) |
| 80 | +glyphs["y"].draw(plPen) |
| 81 | +minY = min(p[1] for p in plPen.pointList) |
| 82 | +maxY = max(p[1] for p in plPen.pointList) |
| 83 | + |
| 84 | +print("""package omegacentauri.mobi.tiltstopwatch; |
| 85 | +
|
| 86 | +import android.graphics.Path; |
| 87 | +
|
| 88 | +public class %s extends MiniFont { |
| 89 | + public %s() { |
| 90 | + super(%s); |
| 91 | + } |
| 92 | + |
| 93 | + public void addFontData() { |
| 94 | + defineFontSize(%gf); |
| 95 | +""" % (className, className, "true" if maximizeDigitBounds else "false", maxY-minY)) |
| 96 | + |
| 97 | +def getGlyph(c): |
| 98 | + try: |
| 99 | + return glyphs[map[ord(c)]] |
| 100 | + except: |
| 101 | + if c == '\u2212': |
| 102 | + return glyphs[map[ord('-')]] |
| 103 | + else: |
| 104 | + raise KeyError() |
| 105 | + |
| 106 | +for c in charsToDump: |
| 107 | + glyph = getGlyph(c) |
| 108 | + |
| 109 | + print(" addCharacter((char)%d,%gf,%gf,new PathMaker() {" % (ord(c),glyph.width,glyph.lsb)) |
| 110 | + print(" @Override") |
| 111 | + print(" public Path makePath() {") |
| 112 | + print(" Path path = new Path();") |
| 113 | + |
| 114 | + glyph.draw(MyPen(indent=" ", transformation=[[1,0,0],[0,-1,0],[0,0,1]])) |
| 115 | + |
| 116 | + print(" return path;") |
| 117 | + print(" }") |
| 118 | + print(" });") |
| 119 | + |
| 120 | + |
| 121 | +for c in charsToNarrow: |
| 122 | + print(" tweakWidth((char)%d,%gf);" % (ord(c),getGlyph(c).width*narrowFraction)) |
| 123 | + |
| 124 | +if equalizeWidths: |
| 125 | + maxW = max(getGlyph(c).width for c in equalizeWidths) |
| 126 | + for c in equalizeWidths: |
| 127 | + if getGlyph(c).width != maxW: |
| 128 | + print(" tweakWidth((char)%d,%gf);" % (ord(c),maxW)) |
| 129 | + |
| 130 | +print(" }") |
| 131 | +print("}") |
0 commit comments