From 0d5d786360b64d4e789b4311fe54f1180a6c302a Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Fri, 13 Nov 2015 13:37:56 -0800 Subject: [italics] Fix whitespace --- scripts/lib/fontbuild/alignpoints.py | 27 +++++++---- scripts/lib/fontbuild/curveFitPen.py | 91 ++++++++++++++++++------------------ scripts/lib/fontbuild/italics.py | 30 ++++++++---- 3 files changed, 83 insertions(+), 65 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/alignpoints.py b/scripts/lib/fontbuild/alignpoints.py index 1133716..76581a5 100644 --- a/scripts/lib/fontbuild/alignpoints.py +++ b/scripts/lib/fontbuild/alignpoints.py @@ -28,7 +28,7 @@ def alignCorners(glyph, va, subsegments): # if seg.type == "line": # subIndex = subsegmentIndex(i,j,subsegments) # out[subIndex] = alignPoints(va[subIndex]) - + for i,c in enumerate(subsegments): segmentCount = len(glyph.contours[i].segments) n = len(c) @@ -66,7 +66,7 @@ def alignCorners(glyph, va, subsegments): def subsegmentIndex(contourIndex, segmentIndex, subsegments): # This whole thing is so dumb. Need a better data model for subsegments - + contourOffset = 0 for i,c in enumerate(subsegments): if i == contourIndex: @@ -77,10 +77,11 @@ def subsegmentIndex(contourIndex, segmentIndex, subsegments): startIndex = subsegments[contourIndex][segmentIndex-1][0] segmentCount = subsegments[contourIndex][segmentIndex][1] endIndex = (startIndex + segmentCount + 1) % (n) - + indices = np.array([(startIndex + i) % (n) + contourOffset for i in range(segmentCount + 1)]) return indices + def alignPoints(pts, start=None, end=None): if start == None or end == None: start, end = fitLine(pts) @@ -89,6 +90,7 @@ def alignPoints(pts, start=None, end=None): out[i] = nearestPoint(start, end, p) return out + def findCorner(pp, nn): if len(pp) < 4 or len(nn) < 4: assert 0, "line too short to fit" @@ -96,34 +98,36 @@ def findCorner(pp, nn): nStart,nEnd = fitLine(nn) prev = pEnd - pStart next = nEnd - nStart - # print int(np.arctan2(prev[1],prev[0]) / math.pi * 180), + # print int(np.arctan2(prev[1],prev[0]) / math.pi * 180), # print int(np.arctan2(next[1],next[0]) / math.pi * 180) # if lines are parallel, return simple average of end and start points - if np.dot(prev / np.linalg.norm(prev), + if np.dot(prev / np.linalg.norm(prev), next / np.linalg.norm(next)) > .999999: # print "parallel lines", np.arctan2(prev[1],prev[0]), np.arctan2(next[1],next[0]) # print prev, next assert 0, "parallel lines" return lineIntersect(pStart, pEnd, nStart, nEnd) + def lineIntersect((x1,y1),(x2,y2),(x3,y3),(x4,y4)): x12 = x1 - x2 x34 = x3 - x4 y12 = y1 - y2 y34 = y3 - y4 - + det = x12 * y34 - y12 * x34 if det == 0: print "parallel!" - + a = x1 * y2 - y1 * x2 b = x3 * y4 - y3 * x4 - + x = (a * x34 - b * x12) / det y = (a * y34 - b * y12) / det - + return (x,y) + def fitLineLSQ(pts): "returns a line fit with least squares. Fails for vertical lines" n = len(pts) @@ -133,6 +137,7 @@ def fitLineLSQ(pts): line = lstsq(a,pts[:,1])[0] return line + def fitLine(pts): """returns a start vector and direction vector Assumes points segments that already form a somewhat smooth line @@ -147,7 +152,8 @@ def fitLine(pts): direction = np.mean(a[1:-1], axis=0) start = np.mean(pts[1:-1], axis=0) return start, start+direction - + + def nearestPoint(a,b,c): "nearest point to point c on line a_b" magnitude = np.linalg.norm(b-a) @@ -155,6 +161,7 @@ def nearestPoint(a,b,c): raise Exception, "Line segment cannot be 0 length" return (b-a) * np.dot((c-a) / magnitude, (b-a) / magnitude) + a + # pts = np.array([[1,1],[2,2],[3,3],[4,4]]) # pts2 = np.array([[1,0],[2,0],[3,0],[4,0]]) # print alignPoints(pts2, start = pts[0], end = pts[0]+pts[0]) diff --git a/scripts/lib/fontbuild/curveFitPen.py b/scripts/lib/fontbuild/curveFitPen.py index 7c232c0..6ef42da 100644 --- a/scripts/lib/fontbuild/curveFitPen.py +++ b/scripts/lib/fontbuild/curveFitPen.py @@ -17,6 +17,7 @@ __all__ = ["SubsegmentPen","SubsegmentsToCurvesPen", "segmentGlyph", "fitGlyph"] + from fontTools.pens.basePen import BasePen from fontTools.misc import bezierTools from robofab.pens.pointPen import AbstractPointPen @@ -27,15 +28,17 @@ from numpy import array as v from random import random from robofab.pens.pointPen import BasePointToSegmentPen + + class SubsegmentsToCurvesPointPen(BasePointToSegmentPen): def __init__(self, glyph, subsegmentGlyph, subsegments): BasePointToSegmentPen.__init__(self) self.glyph = glyph self.subPen = SubsegmentsToCurvesPen(None, glyph.getPen(), subsegmentGlyph, subsegments) - + def setMatchTangents(self, b): self.subPen.matchTangents = b - + def _flushContour(self, segments): # # adapted from robofab.pens.adapterPens.rfUFOPointPen @@ -56,13 +59,13 @@ class SubsegmentsToCurvesPointPen(BasePointToSegmentPen): self.subPen.setLastSmooth(True) if segmentType == 'line': del segments[-1] - + self.subPen.moveTo(movePt) - + # do the rest of the segments for segmentType, points in segments: isSmooth = True in [smooth for pt, smooth, name, kwargs in points] - pp = [pt for pt, smooth, name, kwargs in points] + pp = [pt for pt, smooth, name, kwargs in points] if segmentType == "line": assert len(pp) == 1 if isSmooth: @@ -73,17 +76,18 @@ class SubsegmentsToCurvesPointPen(BasePointToSegmentPen): assert len(pp) == 3 if isSmooth: self.subPen.smoothCurveTo(*pp) - else: + else: self.subPen.curveTo(*pp) elif segmentType == "qcurve": assert 0, "qcurve not supported" else: assert 0, "illegal segmentType: %s" % segmentType self.subPen.closePath() - + def addComponent(self, glyphName, transform): self.subPen.addComponent(glyphName, transform) + class SubsegmentsToCurvesPen(BasePen): def __init__(self, glyphSet, otherPen, subsegmentGlyph, subsegments): BasePen.__init__(self, None) @@ -95,10 +99,10 @@ class SubsegmentsToCurvesPen(BasePen): self.lastPoint = (0,0) self.lastSmooth = False self.nextSmooth = False - + def setLastSmooth(self, b): self.lastSmooth = b - + def _moveTo(self, (x, y)): self.contourIndex += 1 self.segmentIndex = 0 @@ -106,7 +110,7 @@ class SubsegmentsToCurvesPen(BasePen): p = self.ssglyph.contours[self.contourIndex][0].points[0] self.otherPen.moveTo((p.x, p.y)) self.lastPoint = (x,y) - + def _lineTo(self, (x, y)): self.segmentIndex += 1 index = self.subsegments[self.contourIndex][self.segmentIndex][0] @@ -114,39 +118,39 @@ class SubsegmentsToCurvesPen(BasePen): self.otherPen.lineTo((p.x, p.y)) self.lastPoint = (x,y) self.lastSmooth = False - + def smoothLineTo(self, (x, y)): self.lineTo((x,y)) self.lastSmooth = True - + def smoothCurveTo(self, (x1, y1), (x2, y2), (x3, y3)): self.nextSmooth = True self.curveTo((x1, y1), (x2, y2), (x3, y3)) self.nextSmooth = False self.lastSmooth = True - - def _curveToOne(self, (x1, y1), (x2, y2), (x3, y3)): + + def _curveToOne(self, (x1, y1), (x2, y2), (x3, y3)): self.segmentIndex += 1 c = self.ssglyph.contours[self.contourIndex] n = len(c) startIndex = (self.subsegments[self.contourIndex][self.segmentIndex-1][0]) segmentCount = (self.subsegments[self.contourIndex][self.segmentIndex][1]) endIndex = (startIndex + segmentCount + 1) % (n) - + indices = [(startIndex + i) % (n) for i in range(segmentCount + 1)] points = np.array([(c[i].points[0].x, c[i].points[0].y) for i in indices]) prevPoint = (c[(startIndex - 1)].points[0].x, c[(startIndex - 1)].points[0].y) nextPoint = (c[(endIndex) % n].points[0].x, c[(endIndex) % n].points[0].y) prevTangent = prevPoint - points[0] nextTangent = nextPoint - points[-1] - + tangent1 = points[1] - points[0] tangent3 = points[-2] - points[-1] prevTangent /= np.linalg.norm(prevTangent) nextTangent /= np.linalg.norm(nextTangent) tangent1 /= np.linalg.norm(tangent1) tangent3 /= np.linalg.norm(tangent3) - + tangent1, junk = self.smoothTangents(tangent1, prevTangent, self.lastSmooth) tangent3, junk = self.smoothTangents(tangent3, nextTangent, self.nextSmooth) if self.matchTangents == True: @@ -162,7 +166,7 @@ class SubsegmentsToCurvesPen(BasePen): self.otherPen.curveTo((cp[1,0], cp[1,1]), (cp[2,0], cp[2,1]), (cp[3,0], cp[3,1])) self.lastPoint = (x3, y3) self.lastSmooth = False - + def smoothTangents(self,t1,t2,forceSmooth = False): if forceSmooth or (abs(t1.dot(t2)) > .95 and norm(t1-t2) > 1): # print t1,t2, @@ -170,15 +174,13 @@ class SubsegmentsToCurvesPen(BasePen): t2 = -t1 # print t1,t2 return t1 / norm(t1), t2 / norm(t2) - - + def _closePath(self): self.otherPen.closePath() - + def _endPath(self): self.otherPen.endPath() - - + def addComponent(self, glyphName, transformation): self.otherPen.addComponent(glyphName, transformation) @@ -189,10 +191,10 @@ class SubsegmentPointPen(BasePointToSegmentPen): self.glyph = glyph self.resolution = resolution self.subPen = SubsegmentPen(None, glyph.getPen()) - + def getSubsegments(self): return self.subPen.subsegments[:] - + def _flushContour(self, segments): # # adapted from robofab.pens.adapterPens.rfUFOPointPen @@ -210,9 +212,9 @@ class SubsegmentPointPen(BasePointToSegmentPen): movePt, smooth, name, kwargs = points[-1] if segmentType == 'line': del segments[-1] - + self.subPen.moveTo(movePt) - + # do the rest of the segments for segmentType, points in segments: points = [pt for pt, smooth, name, kwargs in points] @@ -227,12 +229,13 @@ class SubsegmentPointPen(BasePointToSegmentPen): else: assert 0, "illegal segmentType: %s" % segmentType self.subPen.closePath() - + def addComponent(self, glyphName, transform): self.subPen.addComponent(glyphName, transform) + class SubsegmentPen(BasePen): - + def __init__(self, glyphSet, otherPen, resolution=25): BasePen.__init__(self,glyphSet) self.resolution = resolution @@ -240,7 +243,7 @@ class SubsegmentPen(BasePen): self.subsegments = [] self.startContour = (0,0) self.contourIndex = -1 - + def _moveTo(self, (x, y)): self.contourIndex += 1 self.segmentIndex = 0 @@ -250,7 +253,7 @@ class SubsegmentPen(BasePen): self.startContour = (x,y) self.lastPoint = (x,y) self.otherPen.moveTo((x,y)) - + def _lineTo(self, (x, y)): count = self.stepsForSegment((x,y),self.lastPoint) if count < 1: @@ -262,7 +265,7 @@ class SubsegmentPen(BasePen): y1 = self.lastPoint[1] + (y - self.lastPoint[1]) * i/float(count) self.otherPen.lineTo((x1,y1)) self.lastPoint = (x,y) - + def _curveToOne(self, (x1, y1), (x2, y2), (x3, y3)): count = self.stepsForSegment((x3,y3),self.lastPoint) if count < 2: @@ -277,46 +280,45 @@ class SubsegmentPen(BasePen): for i in range(count): self.otherPen.lineTo((x[i],y[i])) self.lastPoint = (x3,y3) - + def _closePath(self): if not (self.lastPoint[0] == self.startContour[0] and self.lastPoint[1] == self.startContour[1]): self._lineTo(self.startContour) self.otherPen.closePath() - + def _endPath(self): self.otherPen.endPath() - + def addComponent(self, glyphName, transformation): self.otherPen.addComponent(glyphName, transformation) - + def stepsForSegment(self, p1, p2): dist = np.linalg.norm(v(p1) - v(p2)) out = int(dist / self.resolution) return out - + def renderCurve(self,p,count): curvePoints = [] t = 1.0 / float(count) temp = t * t - + f = p[0] fd = 3 * (p[1] - p[0]) * t fdd_per_2 = 3 * (p[0] - 2 * p[1] + p[2]) * temp fddd_per_2 = 3 * (3 * (p[1] - p[2]) + p[3] - p[0]) * temp * t - + fddd = fddd_per_2 + fddd_per_2 fdd = fdd_per_2 + fdd_per_2 fddd_per_6 = fddd_per_2 * (1.0 / 3) - + for i in range(count): f = f + fd + fdd_per_2 + fddd_per_6 fd = fd + fdd + fddd_per_2 fdd = fdd + fddd fdd_per_2 = fdd_per_2 + fddd_per_2 curvePoints.append(f) - - return curvePoints + return curvePoints def fitBezierSimple(pts): @@ -363,14 +365,14 @@ def fitBezier(pts,tangent0=None,tangent3=None): pout = pts.copy() pout[:,0] -= (T[:,0] * pts[0,0]) + (T[:,3] * pts[-1,0]) pout[:,1] -= (T[:,0] * pts[0,1]) + (T[:,3] * pts[-1,1]) - + TT = np.zeros((n*2,4)) for i in range(n): for j in range(2): TT[i*2,j*2] = T[i,j+1] TT[i*2+1,j*2+1] = T[i,j+1] pout = pout.reshape((n*2,1),order="C") - + if tangent0 != None and tangent3 != None: tangentConstraintsT = np.array([ [tangent0[1], -tangent0[0], 0, 0], @@ -414,4 +416,3 @@ if __name__ == '__main__': [1,1] ]) print np.array(p.renderCurve(pts,10)) * 10 - diff --git a/scripts/lib/fontbuild/italics.py b/scripts/lib/fontbuild/italics.py index c889bd5..b1db984 100644 --- a/scripts/lib/fontbuild/italics.py +++ b/scripts/lib/fontbuild/italics.py @@ -33,11 +33,11 @@ def italicizeGlyph(f, g, angle=10, stemWidth=185): m = Transform(1, 0, slope, 1, 0, 0) xoffset, junk = m.transformPoint((0, MEAN_YCENTER)) m = Transform(.97, 0, slope, 1, xoffset, 0) - + if len(glyph) > 0: g2 = italicize(f[g.name], angle, xoffset=xoffset, stemWidth=stemWidth) f.insertGlyph(g2, g.name) - + transformFLGlyphMembers(f[g.name], m) if unic > 0xFFFF: #restore unicode @@ -53,12 +53,12 @@ def italicize(glyph, angle=12, stemWidth=180, xoffset=-50): grad = mapEdges(lambda a,(p,n): normalize(p-a), va, e) cornerWeights = mapEdges(lambda a,(p,n): normalize(p-a).dot(normalize(a-n)), grad, e)[:,0].reshape((-1,1)) smooth = np.ones((n,1)) * CURVE_CORRECTION_WEIGHT - + controlPoints = findControlPointsInMesh(glyph, va, subsegments) smooth[controlPoints > 0] = 1 smooth[cornerWeights < .6] = CORNER_WEIGHT # smooth[cornerWeights >= .9999] = 1 - + out = va.copy() hascurves = False for c in glyph.contours: @@ -80,13 +80,13 @@ def italicize(glyph, angle=12, stemWidth=180, xoffset=-50): centerSkew = skewMesh(center.dot(np.array([[.97,0],[0,1]])), angle * .9) out = outCorrected + (centerSkew - center) out[:,1] = outCorrected[:,1] - + smooth = np.ones((n,1)) * .1 out = alignCorners(glyph, out, subsegments) out = copyMeshDetails(skewMesh(va, angle), out, e, 7, smooth=smooth) # grad = mapEdges(lambda a,(p,n): normalize(p-a), skewMesh(outCorrected, angle*.9), e) # out = recompose(out, grad, e, smooth=smooth) - + out = skewMesh(out, angle * .1) out[:,0] += xoffset # out[:,1] = outCorrected[:,1] @@ -132,6 +132,7 @@ def glyphToMesh(g): offset += len(c) return np.array(points), edges + def meshToGlyph(points, g): g1 = g.copy() j = 0 @@ -144,6 +145,7 @@ def meshToGlyph(points, g): j += 1 return g1 + def quantizeGradient(grad, book=None): if book == None: book = np.array([(1,0),(0,1),(0,-1),(-1,0)]) @@ -153,6 +155,7 @@ def quantizeGradient(grad, book=None): out[i] = normalize(v) return out + def findControlPointsInMesh(glyph, va, subsegments): controlPointIndices = np.zeros((len(va),1)) index = 0 @@ -166,7 +169,6 @@ def findControlPointsInMesh(glyph, va, subsegments): return controlPointIndices - def recompose(v, grad, e, smooth=1, P=None, distance=None): n = len(v) if distance == None: @@ -183,6 +185,7 @@ def recompose(v, grad, e, smooth=1, P=None, distance=None): out[:,i] = cg(P, f[:,i])[0] return out + def mP(v,e): n = len(v) M = np.zeros((n,n)) @@ -193,18 +196,21 @@ def mP(v,e): M[i,i] = 2 return M + def normalize(v): n = np.linalg.norm(v) if n == 0: return v return v/n + def mapEdges(func,v,e,*args): b = v.copy() for i, edges in e.iteritems(): b[i] = func(v[i], [v[j] for j in edges], *args) return b + def getNormal(a,b,c): "Assumes TT winding direction" p = np.roll(normalize(b - a), 1) @@ -214,19 +220,23 @@ def getNormal(a,b,c): # print p, n, normalize((p + n) * .5) return normalize((p + n) * .5) + def edgeNormals(v,e): "Assumes a mesh where each vertex has exactly least two edges" return mapEdges(lambda a,(p,n) : getNormal(a,p,n),v,e) + def rangePrevNext(count): c = np.arange(count,dtype=int) r = np.vstack((c, np.roll(c, 1), np.roll(c, -1))) return r.T + def skewMesh(v,angle): slope = np.tanh([math.pi * angle / 180]) return v.dot(np.array([[1,0],[slope,1]])) + def labelConnected(e): label = 0 labels = np.zeros((len(e),1)) @@ -236,6 +246,7 @@ def labelConnected(e): label += 1 return labels + def copyGradDetails(a,b,e,scale=15): n = len(a) labels = labelConnected(e) @@ -245,6 +256,7 @@ def copyGradDetails(a,b,e,scale=15): out[mask,:] = gaussian(b[mask,:], scale, mode="wrap", axis=0) + a[mask,:] - gaussian(a[mask,:], scale, mode="wrap", axis=0) return out + def copyMeshDetails(va,vb,e,scale=5,smooth=.01): gradA = mapEdges(lambda a,(p,n): normalize(p-a), va, e) gradB = mapEdges(lambda a,(p,n): normalize(p-a), vb, e) @@ -253,8 +265,6 @@ def copyMeshDetails(va,vb,e,scale=5,smooth=.01): return recompose(vb, grad, e, smooth=smooth) - - def condenseGlyph(glyph, scale=.8, stemWidth=185): ga, subsegments = segmentGlyph(glyph, 25) va, e = glyphToMesh(ga) @@ -273,7 +283,7 @@ def condenseGlyph(glyph, scale=.8, stemWidth=185): # cornerWeights = mapEdges(lambda a,(p,n): normalize(p-a).dot(normalize(a-n)), grad, e)[:,0].reshape((-1,1)) # smooth = np.ones((n,1)) * .1 # smooth[cornerWeights < .6] = 10 - # + # # grad2 = quantizeGradient(grad).astype(float) # grad2 = copyGradDetails(grad, grad2, e, scale=10) # grad2 = mapEdges(lambda a,e: normalize(a), grad2, e) -- cgit v1.2.3 From ceb4ae1b523cb0160dbf2ac57b770db0761c68d9 Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Fri, 13 Nov 2015 13:39:25 -0800 Subject: [italics] Fix import order, remove unused imports --- scripts/lib/fontbuild/alignpoints.py | 4 +++- scripts/lib/fontbuild/curveFitPen.py | 8 ++------ scripts/lib/fontbuild/italics.py | 20 ++++++++++---------- 3 files changed, 15 insertions(+), 17 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/alignpoints.py b/scripts/lib/fontbuild/alignpoints.py index 76581a5..e3bb539 100644 --- a/scripts/lib/fontbuild/alignpoints.py +++ b/scripts/lib/fontbuild/alignpoints.py @@ -13,9 +13,11 @@ # limitations under the License. +import math + import numpy as np from numpy.linalg import lstsq -import math + def alignCorners(glyph, va, subsegments): out = va.copy() diff --git a/scripts/lib/fontbuild/curveFitPen.py b/scripts/lib/fontbuild/curveFitPen.py index 6ef42da..c2b90ac 100644 --- a/scripts/lib/fontbuild/curveFitPen.py +++ b/scripts/lib/fontbuild/curveFitPen.py @@ -19,14 +19,10 @@ __all__ = ["SubsegmentPen","SubsegmentsToCurvesPen", "segmentGlyph", "fitGlyph"] from fontTools.pens.basePen import BasePen -from fontTools.misc import bezierTools -from robofab.pens.pointPen import AbstractPointPen -from robofab.pens.adapterPens import PointToSegmentPen, GuessSmoothPointPen import numpy as np -from numpy.linalg import norm from numpy import array as v -from random import random - +from numpy.linalg import norm +from robofab.pens.adapterPens import GuessSmoothPointPen from robofab.pens.pointPen import BasePointToSegmentPen diff --git a/scripts/lib/fontbuild/italics.py b/scripts/lib/fontbuild/italics.py index b1db984..83b123f 100644 --- a/scripts/lib/fontbuild/italics.py +++ b/scripts/lib/fontbuild/italics.py @@ -13,12 +13,18 @@ # limitations under the License. +import math + from fontTools.misc.transform import Transform -from robofab.world import RFont -from time import clock import numpy as np -import math -from alignpoints import alignCorners +from numpy.linalg import norm +from scipy.sparse.linalg import cg +from scipy.ndimage.filters import gaussian_filter1d as gaussian +from scipy.cluster.vq import vq, whiten + +from fontbuild.alignpoints import alignCorners +from fontbuild.curveFitPen import fitGlyph, segmentGlyph + def italicizeGlyph(f, g, angle=10, stemWidth=185): unic = g.unicode #save unicode @@ -111,13 +117,7 @@ def transformFLGlyphMembers(g, m, transformAnchors = True): a.x = aa[0] # a.x,a.y = (aa[0] - p[0], aa[1] - p[1]) # a.x = a.x - m[4] - -from curveFitPen import fitGlyph,segmentGlyph -from numpy.linalg import norm -from scipy.sparse.linalg import cg -from scipy.ndimage.filters import gaussian_filter1d as gaussian -from scipy.cluster.vq import vq, kmeans2, whiten def glyphToMesh(g): points = [] -- cgit v1.2.3 From 8b5f2c40e043ac354b74481919d25b85f1136d41 Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Thu, 19 Nov 2015 15:23:24 -0800 Subject: [italics] Work around RoboFab-related issues This is (hopefully) a temporary hack until a more robust solution to the issue is found. Basically the problem is that RoboFab pens do float-to-float comparisons to decide whether to remove duplicate points from contours, and breaks with BooleanOperations output (which can include point coordinates with very small fractional components). The italicizing code assumes certain behavior from RoboFab pens and can't handle duplicate points being kept. --- scripts/lib/fontbuild/Build.py | 14 ++------------ scripts/lib/fontbuild/curveFitPen.py | 8 ++++++++ 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index d1e870a..5d92705 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -120,18 +120,8 @@ class FontProject: if g.name == "uniFFFD": continue - - # 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) + + removeGlyphOverlap(g) if g.name in self.lessItalic: italicizeGlyph(f, g, 9, stemWidth=stemWidth) diff --git a/scripts/lib/fontbuild/curveFitPen.py b/scripts/lib/fontbuild/curveFitPen.py index c2b90ac..f7c0cae 100644 --- a/scripts/lib/fontbuild/curveFitPen.py +++ b/scripts/lib/fontbuild/curveFitPen.py @@ -280,6 +280,14 @@ class SubsegmentPen(BasePen): def _closePath(self): if not (self.lastPoint[0] == self.startContour[0] and self.lastPoint[1] == self.startContour[1]): self._lineTo(self.startContour) + + # round values used by otherPen (a RoboFab SegmentToPointPen) to decide + # whether to delete duplicate points at start and end of contour + #TODO(jamesgk) figure out why we have to do this hack, then remove it + c = self.otherPen.contour + for i in [0, -1]: + c[i] = [[round(n, 5) for n in c[i][0]]] + list(c[i][1:]) + self.otherPen.closePath() def _endPath(self): -- cgit v1.2.3 From b9db24ac21becece78cdf011921d1416046dc159 Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Thu, 19 Nov 2015 15:42:48 -0800 Subject: [italics] Add some comments It's not much, but maybe a start.... --- scripts/lib/fontbuild/italics.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/italics.py b/scripts/lib/fontbuild/italics.py index 83b123f..51d1f96 100644 --- a/scripts/lib/fontbuild/italics.py +++ b/scripts/lib/fontbuild/italics.py @@ -53,6 +53,8 @@ def italicizeGlyph(f, g, angle=10, stemWidth=185): def italicize(glyph, angle=12, stemWidth=180, xoffset=-50): CURVE_CORRECTION_WEIGHT = .03 CORNER_WEIGHT = 10 + + # decompose the glyph into smaller segments ga, subsegments = segmentGlyph(glyph,25) va, e = glyphToMesh(ga) n = len(va) @@ -79,14 +81,19 @@ def italicize(glyph, angle=12, stemWidth=180, xoffset=-50): # out = copyMeshDetails(va, out, e, 6) else: outCorrected = out + + # create a transform for italicizing normals = edgeNormals(out, e) center = va + normals * stemWidth * .4 if stemWidth > 130: center[:, 0] = va[:, 0] * .7 + center[:,0] * .3 centerSkew = skewMesh(center.dot(np.array([[.97,0],[0,1]])), angle * .9) + + # apply the transform out = outCorrected + (centerSkew - center) out[:,1] = outCorrected[:,1] + # make some corrections smooth = np.ones((n,1)) * .1 out = alignCorners(glyph, out, subsegments) out = copyMeshDetails(skewMesh(va, angle), out, e, 7, smooth=smooth) @@ -101,6 +108,8 @@ def italicize(glyph, angle=12, stemWidth=180, xoffset=-50): # gOut.width *= .97 # gOut.width += 10 # return gOut + + # recompose the glyph into original segments return fitGlyph(glyph, gOut, subsegments) -- cgit v1.2.3 From 21ef39becd62519e32accdf2f07554571fc46bfa Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Wed, 14 Oct 2015 11:28:53 -0700 Subject: Fix import order in Build.py --- scripts/lib/fontbuild/Build.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index 5d92705..f29c727 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -13,23 +13,25 @@ # limitations under the License. +import ConfigParser +import os +import sys + from booleanOperations import BooleanOperationManager +from fontTools.misc.transform import Transform from robofab.world import OpenFont -from fontbuild.mix import Mix,Master,narrowFLGlyph -from fontbuild.instanceNames import setNamesRF -from fontbuild.italics import italicizeGlyph + from fontbuild.convertCurves import glyphCurvesToQuadratic -from fontbuild.mitreGlyph import mitreGlyph +from fontbuild.decomposeGlyph import decomposeGlyph +from fontbuild.features import readFeatureFile, writeFeatureFile from fontbuild.generateGlyph import generateGlyph -from fontTools.misc.transform import Transform +from fontbuild.instanceNames import setNamesRF +from fontbuild.italics import italicizeGlyph from fontbuild.kerning import makeKernFeature -from fontbuild.features import readFeatureFile, writeFeatureFile from fontbuild.markFeature import GenerateFeature_mark +from fontbuild.mitreGlyph import mitreGlyph +from fontbuild.mix import Mix,Master,narrowFLGlyph from fontbuild.mkmkFeature import GenerateFeature_mkmk -from fontbuild.decomposeGlyph import decomposeGlyph -import ConfigParser -import os -import sys class FontProject: -- cgit v1.2.3 From e8c9488af391731a94e9c47b63e926f3d7e14c6e Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Tue, 3 Nov 2015 13:28:11 -0800 Subject: Generate TTFs with ufo2ft --- scripts/lib/fontbuild/Build.py | 74 ++++++++------------ scripts/lib/fontbuild/kerning.py | 112 ----------------------------- scripts/lib/fontbuild/markFeature.py | 132 ++++++++--------------------------- scripts/lib/fontbuild/mkmkFeature.py | 87 ----------------------- 4 files changed, 60 insertions(+), 345 deletions(-) delete mode 100644 scripts/lib/fontbuild/kerning.py delete mode 100755 scripts/lib/fontbuild/mkmkFeature.py (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index f29c727..34a672e 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -18,20 +18,19 @@ import os import sys from booleanOperations import BooleanOperationManager +from convert_curves import fonts_to_quadratic from fontTools.misc.transform import Transform from robofab.world import OpenFont +from ufo2ft import compileOTF, compileTTF -from fontbuild.convertCurves import glyphCurvesToQuadratic from fontbuild.decomposeGlyph import decomposeGlyph from fontbuild.features import readFeatureFile, writeFeatureFile from fontbuild.generateGlyph import generateGlyph from fontbuild.instanceNames import setNamesRF from fontbuild.italics import italicizeGlyph -from fontbuild.kerning import makeKernFeature -from fontbuild.markFeature import GenerateFeature_mark +from fontbuild.markFeature import RobotoFeatureCompiler from fontbuild.mitreGlyph import mitreGlyph from fontbuild.mix import Mix,Master,narrowFLGlyph -from fontbuild.mkmkFeature import GenerateFeature_mkmk class FontProject: @@ -68,8 +67,8 @@ class FontProject: self.buildnumber = self.loadBuildNumber() self.buildOTF = False - self.autohintOTF = False - self.buildTTF = False + self.compatible = False + self.generatedFonts = [] def loadBuildNumber(self): @@ -155,33 +154,38 @@ class FontProject: setNamesRF(f, n, foundry=self.config.get('main', 'foundry'), version=self.config.get('main', 'version')) - cleanCurves(f) + if not self.compatible: + cleanCurves(f) deleteGlyphs(f, self.deleteList) if kern: log(">> Generating kern classes") readFeatureFile(f, self.ot_kerningclasses) - makeKernFeature(f, self.ot_kerningclasses) log(">> Generating font files") - GenerateFeature_mark(f) - GenerateFeature_mkmk(f) ufoName = self.generateOutputPath(f, "ufo") f.save(ufoName) + self.generatedFonts.append(ufoName) if self.buildOTF: log(">> Generating OTF file") newFont = OpenFont(ufoName) otfName = self.generateOutputPath(f, "otf") - builtSuccessfully = saveOTF(newFont, otfName, autohint=self.autohintOTF) - if not builtSuccessfully: - sys.exit(1) + saveOTF(newFont, otfName) - if self.buildTTF: - log(">> Generating TTF file") - import fontforge - otFont = fontforge.open(otfName) - otFont.generate(self.generateOutputPath(f, "ttf")) + def generateTTFs(self): + """Build TTF for each font generated since last call to generateTTFs.""" + + fonts = [OpenFont(ufo) for ufo in self.generatedFonts] + log(">> Converting curves to quadratic") + fonts_to_quadratic(fonts, self.compatible) + + log(">> Generating TTF files") + for font in fonts: + ttfName = self.generateOutputPath(font, "ttf") + log(os.path.basename(ttfName)) + saveOTF(font, ttfName, truetype=True) + self.generatedFonts = [] def transformGlyphMembers(g, m): @@ -266,30 +270,12 @@ def removeGlyphOverlap(glyph): manager.union(contours, glyph.getPointPen()) -def saveOTF(font, destFile, autohint=False): - """Save a RoboFab font as an OTF binary using ufo2fdk. - - Returns True on success, False otherwise. - """ - - from ufo2fdk import OTFCompiler - - # glyphs with multiple unicode values must be split up, due to FontTool's - # use of a name -> UV dictionary during cmap compilation - for glyph in font: - if len(glyph.unicodes) > 1: - newUV = glyph.unicodes.pop() - newGlyph = font.newGlyph("uni%04X" % newUV) - newGlyph.appendComponent(glyph.name) - newGlyph.unicode = newUV - newGlyph.width = glyph.width - - compiler = OTFCompiler() - reports = compiler.compile(font, destFile, autohint=autohint) - if autohint: - print reports["autohint"] - print reports["makeotf"] +def saveOTF(font, destFile, truetype=False): + """Save a RoboFab font as an OTF binary using ufo2fdk.""" - successMsg = ("makeotfexe [NOTE] Wrote new font file '%s'." % - os.path.basename(destFile)) - return successMsg in reports["makeotf"] + if truetype: + compiler = compileTTF + else: + compiler = compileOTF + otf = compiler(font, featureCompilerClass=RobotoFeatureCompiler) + otf.save(destFile) diff --git a/scripts/lib/fontbuild/kerning.py b/scripts/lib/fontbuild/kerning.py deleted file mode 100644 index c93e303..0000000 --- a/scripts/lib/fontbuild/kerning.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2015 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -from feaTools import parser -from feaTools.writers.baseWriter import AbstractFeatureWriter - - -class KernFeatureWriter(AbstractFeatureWriter): - """Generates a kerning feature based on glyph class definitions. - - Uses the kerning rules contained in an RFont's kerning attribute, as well as - glyph classes from parsed OTF text. Class-based rules are set based on the - existing rules for their key glyphs. - """ - - def __init__(self, font): - self.kerning = font.kerning - self.leftClasses = [] - self.rightClasses = [] - self.classSizes = {} - - def write(self, linesep="\n"): - """Write kern feature.""" - - # maintain collections of different rule types - leftClassKerning, rightClassKerning, classPairKerning = {}, {}, {} - for leftName, leftContents in self.leftClasses: - leftKey = leftContents[0] - - # collect rules with two classes - for rightName, rightContents in self.rightClasses: - rightKey = rightContents[0] - pair = leftKey, rightKey - kerningVal = self.kerning[pair] - if kerningVal is None: - continue - classPairKerning[leftName, rightName] = kerningVal - self.kerning.remove(pair) - - # collect rules with left class and right glyph - for pair, kerningVal in self.kerning.getLeft(leftKey): - leftClassKerning[leftName, pair[1]] = kerningVal - self.kerning.remove(pair) - - # collect rules with left glyph and right class - for rightName, rightContents in self.rightClasses: - rightKey = rightContents[0] - for pair, kerningVal in self.kerning.getRight(rightKey): - rightClassKerning[pair[0], rightName] = kerningVal - self.kerning.remove(pair) - - # write the feature - self.ruleCount = 0 - lines = ["feature kern {"] - lines.append(self._writeKerning(self.kerning, linesep)) - lines.append(self._writeKerning(leftClassKerning, linesep, True)) - lines.append(self._writeKerning(rightClassKerning, linesep, True)) - lines.append(self._writeKerning(classPairKerning, linesep)) - lines.append("} kern;") - return linesep.join(lines) - - def _writeKerning(self, kerning, linesep, enum=False): - """Write kerning rules for a mapping of pairs to values.""" - - lines = [] - enum = "enum " if enum else "" - pairs = kerning.items() - pairs.sort() - for (left, right), val in pairs: - if enum: - rulesAdded = (self.classSizes.get(left, 1) * - self.classSizes.get(right, 1)) - else: - rulesAdded = 1 - self.ruleCount += rulesAdded - if self.ruleCount > 1024: - lines.append(" subtable;") - self.ruleCount = rulesAdded - lines.append(" %spos %s %s %d;" % (enum, left, right, val)) - return linesep.join(lines) - - def classDefinition(self, name, contents): - """Store a class definition as either a left- or right-hand class.""" - - if not name.startswith("@_"): - return - info = (name, contents) - if name.endswith("_L"): - self.leftClasses.append(info) - elif name.endswith("_R"): - self.rightClasses.append(info) - self.classSizes[name] = len(contents) - - -def makeKernFeature(font, text): - """Add a kern feature to the font, using a KernFeatureWriter.""" - - writer = KernFeatureWriter(font) - parser.parseFeatures(writer, text) - font.features.text += writer.write() diff --git a/scripts/lib/fontbuild/markFeature.py b/scripts/lib/fontbuild/markFeature.py index b617ef6..945cef0 100755 --- a/scripts/lib/fontbuild/markFeature.py +++ b/scripts/lib/fontbuild/markFeature.py @@ -13,105 +13,33 @@ # limitations under the License. -from fontbuild.features import updateFeature - - -aliases = [["uni0430", "a"], ["uni0435", "e"], ["uni0440", "p"], ["uni0441", "c"], ["uni0445", "x"], ["uni0455", "s"], ["uni0456", "i"], ["uni0471", "psi"]] - -def GetAliaseName(gname): - for i in range (len(aliases)): - if (gname == aliases[i][1]): - return aliases[i][0] - return None - -def CreateAccNameList(font, acc_anchor_name, bCombAccentOnly = True): - #combrange = range(0x0300,0x0370) + range(0x1AB0,0x1ABF) + range(0x1DC0,0x1DE0) - lst = [] - for g in font: - if bCombAccentOnly and g.width != 0: #((g.unicode < 0x0300) or (g.unicode > 0x362)): - continue - for anchor in g.anchors: - if acc_anchor_name == anchor.name: - lst.append(g.name) - return lst - -def CreateAccGlyphList(font, acc_list, acc_anchor_name): - g_list = [] - for g in font: - if g.name in acc_list: - for anchor in g.anchors: - if acc_anchor_name == anchor.name: - g_list.append([g.name, anchor.x, anchor.y]) - break - return g_list - - -def CreateGlyphList(font, acc_list, anchor_name): - g_list = [] - for g in font: - if g.name in acc_list: - continue - for anchor in g.anchors: - if anchor_name == anchor.name: - g_list.append([g.name, anchor.x, anchor.y]) - break - return g_list - -def Create_mark_lookup(accent_g_list, base_g_list, lookupname, acc_class, lookAliases = True): - txt = "lookup " + lookupname + " {\n" - - for acc in accent_g_list: - txt += " markClass " + acc[0] + " " + acc_class +";\n" - - for base in base_g_list: - txt += " pos base " + base[0] + " mark " + acc_class + ";\n" - if (lookAliases): - base2 = GetAliaseName(base[0]) - if (None == base2): - continue - txt += " pos base " + base2 + " mark " + acc_class + ";\n" - - txt += "} " + lookupname + ";\n" - - return txt - -##### main ############## -def GenerateFeature_mark(font): - - combination_anchor_list = [ - ["top", "_marktop", True, True], - ["bottom", "_markbottom", True, True], - ["top_dd", "_marktop_dd", True, False], - ["bottom_dd", "_markbottom_dd", True, False], - ["rhotichook", "_markrhotichook", False, False], - ["top0315", "_marktop0315", False, False], - ["parent_top", "_markparent_top", False, False], - ["parenthesses.w1", "_markparenthesses.w1", False, False], - ["parenthesses.w2", "_markparenthesses.w2", False, False], - ["parenthesses.w3", "_markparenthesses.w3", False, False] - ] - - text = "feature mark {\n" - - for n in range(len(combination_anchor_list)): - - accent_name_list = [] - accent_mark_list = [] - base_mark_list = [] - - anchors_pair = combination_anchor_list[n] - anchor_name = anchors_pair[0] - acc_anchor_name = anchors_pair[1] - comb_accent_only = anchors_pair[2] - expand_to_composits = anchors_pair[3] - lookupname = "mark"+`n+1` - classname = "@MC_" + anchor_name - - accent_name_list = CreateAccNameList(font, acc_anchor_name, comb_accent_only) - accent_mark_list = CreateAccGlyphList(font, accent_name_list, acc_anchor_name) - base_mark_list = CreateGlyphList(font, accent_name_list, anchor_name) - text += Create_mark_lookup(accent_mark_list, base_mark_list, lookupname, classname, expand_to_composits) - - text += "} mark;\n" - - updateFeature(font, "mark", text) +from ufo2ft.kernFeatureWriter import KernFeatureWriter +from ufo2ft.makeotfParts import FeatureOTFCompiler + + +class RobotoFeatureCompiler(FeatureOTFCompiler): + def precompile(self): + self.overwriteFeatures = True + + def setupAnchorPairs(self): + self.anchorPairs = [ + ["top", "_marktop", True, True], + ["bottom", "_markbottom", True, True], + ["top_dd", "_marktop_dd", True, False], + ["bottom_dd", "_markbottom_dd", True, False], + ["rhotichook", "_markrhotichook", False, False], + ["top0315", "_marktop0315", False, False], + ["parent_top", "_markparent_top", False, False], + ["parenthesses.w1", "_markparenthesses.w1", False, False], + ["parenthesses.w2", "_markparenthesses.w2", False, False], + ["parenthesses.w3", "_markparenthesses.w3", False, False]] + + self.mkmkAnchorPairs = [ + ["mkmktop", "_marktop"], + ["mkmkbottom_acc", "_markbottom"]] + + def setupAliases(self): + self.aliases = [ + ["a", "uni0430"], ["e", "uni0435"], ["p", "uni0440"], + ["c", "uni0441"], ["x", "uni0445"], ["s", "uni0455"], + ["i", "uni0456"], ["psi", "uni0471"]] diff --git a/scripts/lib/fontbuild/mkmkFeature.py b/scripts/lib/fontbuild/mkmkFeature.py deleted file mode 100755 index 16f9313..0000000 --- a/scripts/lib/fontbuild/mkmkFeature.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2015 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -from fontbuild.features import updateFeature - - -def CreateAccNameList(font, acc_anchor_name): - lst = [] - for g in font: - for anchor in g.anchors: - if acc_anchor_name == anchor.name: - lst.append(g.name) - return lst - -def CreateAccGlyphList(font, acc_list, acc_anchor_name): - g_list = [] - for g in font: - if g.name in acc_list: - for anchor in g.anchors: - if acc_anchor_name == anchor.name: - g_list.append([g.name, anchor.x, anchor.y]) - break - return g_list - - -def CreateGlyphList(font, acc_list, anchor_name): - g_list = [] - for g in font: - for anchor in g.anchors: - if anchor_name == anchor.name: - g_list.append([g.name, anchor.x, anchor.y]) - break - return g_list - -def Create_mkmk1(accent_g_list, base_g_list, lookupname, acc_class): - txt = "lookup " + lookupname + " {\n" - #acc_class = "@MC_mkmk" - for acc in accent_g_list: - txt += " markClass " + acc[0] + " " + acc_class +";\n" - - for base in base_g_list: - txt += " pos mark " + base[0] + " mark " + acc_class + ";\n" - - txt += "} " + lookupname + ";\n" - - return txt - - -##### main ############## -def GenerateFeature_mkmk(font): - text = "feature mkmk {\n" - - accent_name_list = [] - accent_mark_list = [] - base_mark_list = [] - anchor_name = "mkmktop" - acc_anchor_name = "_marktop" - accent_name_list = CreateAccNameList(font, acc_anchor_name) - accent_mark_list = CreateAccGlyphList(font, accent_name_list, acc_anchor_name) - base_mark_list = CreateGlyphList(font, accent_name_list, anchor_name) - text += Create_mkmk1(accent_mark_list, base_mark_list, "mkmk1", "@MC_mkmk_top") - - accent_name_list = [] - accent_mark_list = [] - base_mark_list = [] - anchor_name = "mkmkbottom_acc" - acc_anchor_name = "_markbottom" - accent_name_list = CreateAccNameList(font, acc_anchor_name) - accent_mark_list = CreateAccGlyphList(font, accent_name_list, acc_anchor_name) - base_mark_list = CreateGlyphList(font, accent_name_list, anchor_name) - text += Create_mkmk1(accent_mark_list, base_mark_list, "mkmk2", "@MC_mkmk_bottom") - - text += "} mkmk;\n" - - updateFeature(font, "mkmk", text) -- cgit v1.2.3 From d1d422cd292addb4b59e85e2af1971635f1d923c Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Thu, 19 Nov 2015 16:13:57 -0800 Subject: Update curve conversion calls based on upstream --- scripts/lib/fontbuild/Build.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index 34a672e..a8451f0 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -18,7 +18,7 @@ import os import sys from booleanOperations import BooleanOperationManager -from convert_curves import fonts_to_quadratic +from cu2qu.rf import fonts_to_quadratic from fontTools.misc.transform import Transform from robofab.world import OpenFont from ufo2ft import compileOTF, compileTTF @@ -177,15 +177,20 @@ class FontProject: """Build TTF for each font generated since last call to generateTTFs.""" fonts = [OpenFont(ufo) for ufo in self.generatedFonts] + self.generatedFonts = [] + log(">> Converting curves to quadratic") - fonts_to_quadratic(fonts, self.compatible) + if self.compatible: + fonts_to_quadratic(*fonts, dump_report=True) + else: + for font in fonts: + fonts_to_quadratic(font, dump_report=True) log(">> Generating TTF files") for font in fonts: ttfName = self.generateOutputPath(font, "ttf") log(os.path.basename(ttfName)) saveOTF(font, ttfName, truetype=True) - self.generatedFonts = [] def transformGlyphMembers(g, m): -- cgit v1.2.3 From 09eb72c1feecd1c997c8cccc47532440717e4a5f Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Fri, 20 Nov 2015 17:24:29 -0800 Subject: Change error bound when converting curves This is a small change which passes the threshold at which dots will have eight points instead of four, which makes a noticeable difference in shape. --- scripts/lib/fontbuild/Build.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index a8451f0..041a7ec 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -180,11 +180,14 @@ class FontProject: self.generatedFonts = [] log(">> Converting curves to quadratic") + # using a slightly higher max error (e.g. 0.0025), dots will have fewer + # control points and look noticeably different + max_err = 0.002 if self.compatible: - fonts_to_quadratic(*fonts, dump_report=True) + fonts_to_quadratic(*fonts, max_err=max_err, dump_report=True) else: for font in fonts: - fonts_to_quadratic(font, dump_report=True) + fonts_to_quadratic(font, max_err=max_err, dump_report=True) log(">> Generating TTF files") for font in fonts: -- cgit v1.2.3 From 5b0dcd91995fe60d235bde7c7bb6bdbf0b910e81 Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Mon, 23 Nov 2015 18:54:25 -0800 Subject: Reverse contours before generating TTFs The UFOs store contours in ccw order, and the TrueType spec seems to say they should be cw. The old binaries are cw. --- scripts/lib/fontbuild/Build.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index 041a7ec..5bb0ed6 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -193,6 +193,9 @@ class FontProject: for font in fonts: ttfName = self.generateOutputPath(font, "ttf") log(os.path.basename(ttfName)) + for glyph in font: + for contour in glyph: + contour.reverseContour() saveOTF(font, ttfName, truetype=True) -- cgit v1.2.3 From 7d38014a38dae2303960adac770cd1399f7af032 Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Tue, 24 Nov 2015 15:03:18 -0800 Subject: Another update to curve conversion calls cu2qu is a new library without a currently well-defined API, so these calls have changed and will probably change again. --- scripts/lib/fontbuild/Build.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index 5bb0ed6..be0b79c 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -180,14 +180,14 @@ class FontProject: self.generatedFonts = [] log(">> Converting curves to quadratic") - # using a slightly higher max error (e.g. 0.0025), dots will have fewer - # control points and look noticeably different + # using a slightly higher max error (e.g. 0.0025 em), dots will have + # fewer control points and look noticeably different max_err = 0.002 if self.compatible: - fonts_to_quadratic(*fonts, max_err=max_err, dump_report=True) + fonts_to_quadratic(*fonts, max_err_em=max_err, dump_report=True) else: for font in fonts: - fonts_to_quadratic(font, max_err=max_err, dump_report=True) + fonts_to_quadratic(font, max_err_em=max_err, dump_report=True) log(">> Generating TTF files") for font in fonts: -- cgit v1.2.3 From 5397958ba23710b7146b9351d06ce96da66a19bd Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Fri, 11 Dec 2015 11:57:25 -0800 Subject: Update calls to cu2qu This is hopefully the last time we have to do this. In response to https://github.com/googlei18n/cu2qu/commit/56f36a1b2ab673c25ac81756d5c251909a7d41e2 --- scripts/lib/fontbuild/Build.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index be0b79c..cf07d55 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -184,10 +184,10 @@ class FontProject: # fewer control points and look noticeably different max_err = 0.002 if self.compatible: - fonts_to_quadratic(*fonts, max_err_em=max_err, dump_report=True) + fonts_to_quadratic(fonts, max_err_em=max_err, dump_stats=True) else: for font in fonts: - fonts_to_quadratic(font, max_err_em=max_err, dump_report=True) + fonts_to_quadratic([font], max_err_em=max_err, dump_stats=True) log(">> Generating TTF files") for font in fonts: -- cgit v1.2.3 From db517c3b0639140ebd1516d2669a29d612da1c0b Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Fri, 11 Dec 2015 14:59:36 -0800 Subject: Update calls to ufo2ft Due to changes in https://github.com/jamesgk/ufo2ft/commit/6c46f7050bfdd346c33c1312f07830c48fcc07f2 --- scripts/lib/fontbuild/Build.py | 5 +++-- scripts/lib/fontbuild/markFeature.py | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/Build.py b/scripts/lib/fontbuild/Build.py index cf07d55..a4e5bac 100644 --- a/scripts/lib/fontbuild/Build.py +++ b/scripts/lib/fontbuild/Build.py @@ -28,7 +28,7 @@ from fontbuild.features import readFeatureFile, writeFeatureFile from fontbuild.generateGlyph import generateGlyph from fontbuild.instanceNames import setNamesRF from fontbuild.italics import italicizeGlyph -from fontbuild.markFeature import RobotoFeatureCompiler +from fontbuild.markFeature import RobotoFeatureCompiler, RobotoKernWriter from fontbuild.mitreGlyph import mitreGlyph from fontbuild.mix import Mix,Master,narrowFLGlyph @@ -288,5 +288,6 @@ def saveOTF(font, destFile, truetype=False): compiler = compileTTF else: compiler = compileOTF - otf = compiler(font, featureCompilerClass=RobotoFeatureCompiler) + otf = compiler(font, featureCompilerClass=RobotoFeatureCompiler, + kernWriter=RobotoKernWriter) otf.save(destFile) diff --git a/scripts/lib/fontbuild/markFeature.py b/scripts/lib/fontbuild/markFeature.py index 945cef0..395e537 100755 --- a/scripts/lib/fontbuild/markFeature.py +++ b/scripts/lib/fontbuild/markFeature.py @@ -43,3 +43,8 @@ class RobotoFeatureCompiler(FeatureOTFCompiler): ["a", "uni0430"], ["e", "uni0435"], ["p", "uni0440"], ["c", "uni0441"], ["x", "uni0445"], ["s", "uni0455"], ["i", "uni0456"], ["psi", "uni0471"]] + + +class RobotoKernWriter(KernFeatureWriter): + leftFeaClassRe = r"@_(.+)_L$" + rightFeaClassRe = r"@_(.+)_R$" -- cgit v1.2.3 From bd17627cd66730ba06b9a305d02266c886eb870a Mon Sep 17 00:00:00 2001 From: James Godfrey-Kittle Date: Mon, 14 Dec 2015 17:14:43 -0800 Subject: Don't change copyright in build scripts The copyright message now found in the source files is correct. --- scripts/lib/fontbuild/instanceNames.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts/lib/fontbuild') diff --git a/scripts/lib/fontbuild/instanceNames.py b/scripts/lib/fontbuild/instanceNames.py index 281eb03..890b5a6 100644 --- a/scripts/lib/fontbuild/instanceNames.py +++ b/scripts/lib/fontbuild/instanceNames.py @@ -57,7 +57,7 @@ class InstanceNames: f.info.versionMajor = version f.info.versionMinor = versionMinor f.info.year = self.year - f.info.copyright = "Font data copyright %s %s" %(self.foundry, self.year) + #f.info.copyright = "Font data copyright %s %s" %(self.foundry, self.year) f.info.trademark = "%s is a trademark of %s." %(self.longfamily, self.foundry) f.info.openTypeNameDesigner = "Christian Robertson" -- cgit v1.2.3