def boxdrawing_diagonal(up=True, down=True): t = math.atan2(bh, bw) dx = swl2 / math.sin(t) dy = swl2 / math.cos(t) contours = [] if up: c = fontforge.contour() c.moveTo(bl, bb) c.lineTo(bl, bb + dy) c.lineTo(br - dx, bt) c.lineTo(br, bt) c.lineTo(br, bt - dy) c.lineTo(bl + dx, bb) c.closed = True contours.append(c) if down: c = fontforge.contour() c.moveTo(bl, bt) c.lineTo(bl + dx, bt) c.lineTo(br, bb + dy) c.lineTo(br, bb) c.lineTo(br - dx, bb) c.lineTo(bl, bt - dy) c.closed = True contours.append(c) return contours
def geometric_triangle(rotation=0, black=True): sw = 46 xm = 37 b = bb + (bh - bw + 2 * xm) / 2.0 t = b + (bw - 2 * xm) * math.sin(math.pi / 3) contours = [] c = fontforge.contour() c.moveTo(bl + xm, b) c.lineTo(cx, t) c.lineTo(br - xm, b) c.closed = True contours.append(c) if not black: xm += sw * math.sqrt(3) c = fontforge.contour() c.moveTo(bl + xm, b + sw) c.lineTo(br - xm, b + sw) c.lineTo(cx, t - 2 * sw) c.closed = True contours.append(c) if rotation: cy = (b + t) / 2.0 rotT = psMat.compose(psMat.translate(-cx, -cy), psMat.compose(psMat.rotate(rotation), psMat.translate(cx, cy))) for c in contours: c.transform(rotT) return contours
def add_guides(glyph, direction): f = fontforge.activeFont() guides = f.guide l = glyph.layers[glyph.activeLayer] for c in l: for p in selected_points(c): if direction != "h" and direction != "v" and direction != "hv": return False if direction == "h" or direction == "hv": guide = fontforge.contour() # place an horizontal guideline using point position guide.moveTo(-1000, p.y) guide.lineTo(2000, p.y) guides += guide if direction == "v" or direction == "hv": guide = fontforge.contour() # place a vertical guideline using point position guide.moveTo(p.x, -2000) guide.lineTo(p.x, 3000) guides += guide f.guide = guides glyph.layers[glyph.activeLayer] = l # Is there a better way to refresh the screen? print "done" return True
def add_guides (glyph, direction): f = fontforge.activeFont() guides = f.guide l = glyph.layers[glyph.activeLayer] for c in l: for p in selected_points(c): if direction != 'h' and direction != 'v' and direction != 'hv': return False if direction == 'h' or direction == 'hv': guide = fontforge.contour() #place an horizontal guideline using point position guide.moveTo (-1000, p.y) guide.lineTo (2000, p.y) guides += guide if direction == 'v' or direction == 'hv': guide = fontforge.contour() #place a vertical guideline using point position guide.moveTo (p.x, -2000) guide.lineTo (p.x, 3000) guides += guide f.guide = guides glyph.layers[glyph.activeLayer]=l #Is there a better way to refresh the screen? print 'done' return True
def boxdrawing_arc(xref=False, yref=False): K = 0.5522847498 r = min(bw, bh) / 2.0 Ci = K * (r - swl2) - r Co = K * (r + swl2) - r c = fontforge.contour() c.moveTo(bl, cy + swl2) c.lineTo(cx - r, cy + swl2) c.cubicTo((cx + Ci, cy + swl2), (cx - swl2, cy - Ci), (cx - swl2, cy + r)) c.lineTo(cx - swl2, bt) c.lineTo(cx + swl2, bt) c.lineTo(cx + swl2, cy + r) c.cubicTo((cx + swl2, cy - Co), (cx + Co, cy - swl2), (cx - r, cy - swl2)) c.lineTo(bl, cy - swl2) c.closed = True if xref: c.transform(xrefT) if yref: c.transform(yrefT) return [c]
def split(c, i, t): l = len(c) if 0 < t < 1 and i % 1 == 0 and 0 <= i < l and c[i].on_curve \ and not c[i+1].on_curve and not c[i+2].on_curve \ and c[(i+3)%l].on_curve: qx1 = c[i].x + t * (c[i + 1].x - c[i].x) qy1 = c[i].y + t * (c[i + 1].y - c[i].y) qx2 = c[i + 1].x + t * (c[i + 2].x - c[i + 1].x) qy2 = c[i + 1].y + t * (c[i + 2].y - c[i + 1].y) rx2 = c[i + 2].x + t * (c[(i + 3) % l].x - c[i + 2].x) ry2 = c[i + 2].y + t * (c[(i + 3) % l].y - c[i + 2].y) rx1 = qx2 + t * (rx2 - qx2) ry1 = qy2 + t * (ry2 - qy2) qx2 = qx1 + t * (qx2 - qx1) qy2 = qy1 + t * (qy2 - qy1) qx3 = qx2 + t * (rx1 - qx2) qy3 = qy2 + t * (ry1 - qy2) doublesegment = fontforge.contour() doublesegment.moveTo(c[i].x, c[i].y) doublesegment.cubicTo(qx1, qy1, qx2, qy2, qx3, qy3) doublesegment.cubicTo(rx1, ry1, rx2, ry2, c[(i + 3) % l].x, c[(i + 3) % l].y) if i + 3 == l and c.closed: # end point is starting point c.reverseDirection() # dirty hack because ff2017 is buggy doublesegment.reverseDirection() c[0:4] = doublesegment c.reverseDirection() else: # generic case c[i:i + 4] = doublesegment
def point_list_to_contour(point_list, is_closed, is_quadratic): c = fontforge.contour() c.is_quadratic = is_quadratic c.closed = is_closed for p in point_list: c += p return c
def rect(left, bottom, right, top): c = fontforge.contour() c.moveTo(left, bottom) c.lineTo(left, top) c.lineTo(right, top) c.lineTo(right, bottom) c.closed = True return c
def powerline_triangle(xref=False): c = fontforge.contour() c.moveTo(bl, bt) c.lineTo(br, cy) c.lineTo(bl, bb) c.closed = True if xref: c.transform(xrefT) return [c]
def __init__(self): chisel = fontforge.contour() chisel.moveTo(-56, 7) chisel.lineTo(39, 41) chisel.lineTo(56, -7) chisel.lineTo(-39, -41) chisel.closed = True self.nib = ['polygonal', chisel] self.nibwidth = 112 self.nibheight = 82 super(Chiseltip, self).__init__("BedsteadChiseltip")
def adjust_contour(self, c): # This function just expands dots. if len(c) != 1: return None if self.dotwidth == 0 and self.dotheight == 0: return None newc = fontforge.contour() newc.moveTo(c[0].x + self.dotwidth / 2, c[0].y) newc.lineTo(c[0].x, c[0].y + self.dotheight / 2) newc.lineTo(c[0].x - self.dotwidth / 2, c[0].y) newc.lineTo(c[0].x, c[0].y - self.dotheight / 2) newc.closed = True return newc
def fixContour(glyph): newLayer = fontforge.layer() for contour in glyph.foreground.__iter__(): newContour = fontforge.contour() tmpContour = fontforge.contour() lastX = None; lastY = None firstX = None; firstY = None for point in contour.__iter__(): if (lastX is None) or (lastY is None): lastX = point.x; lastY = point.y firstX = point.x; firstY = point.y newContour += point else: tmpContour += point if point.on_curve: if hypot(point.x - lastX, point.y - lastY) > 3.0: newContour += tmpContour tmpContour = fontforge.contour() lastX = point.x; lastY = point.y if hypot(firstX - lastX, firstY - lastY) > 3.0: newContour += tmpContour newContour.closed = True newLayer += newContour glyph.foreground = newLayer
def powerline_angle(xref=False): t = math.atan2(cy - bb, bw) dx = swl2 / math.sin(t) dy = swl2 / math.cos(t) c = fontforge.contour() c.moveTo(bl, bt) c.lineTo(bl + dx, bt) c.lineTo(br, cy + dy) c.lineTo(br, cy - dy) c.lineTo(bl + dx, bb) c.lineTo(bl, bb) c.lineTo(bl, bb + dy) c.lineTo(br - dx, cy) c.lineTo(bl, bt - dy) c.closed = True if xref: c.transform(xrefT) return [c]
# Point type conversion tests import fontforge co = fontforge.splineCorner cu = fontforge.splineCurve tn = fontforge.splineTangent hv = fontforge.splineHVCurve ff = fontforge.font() g = ff.createMappedChar('a') cl = [(0,0,True,hv),(0,0,False),(5,-1,False),(5,0,True,hv),(5,1,False),(5,3,False),(4,4,True,hv),(3,5,False),(0,3,False),(0,2,True,hv)] c = fontforge.contour() c[:] = cl c.closed = True l = fontforge.layer() l += c g.setLayer(l,1,('select_none','hvcurve')) cc = g.layers[1][0] for (i,t) in [(0,hv),(3,hv),(6,hv),(9,hv)]: if cc[i].type != t: raise ValueError("Type of point " + str(i) + " should be " + str(t) + " rather than " + str(cc[i].type)) g.setLayer(l,1,('select_all','hvcurve','force')) cc = g.layers[1][0] for (i,t) in [(1,False),(2,True),(4,True),(5,False),(7,False),(8,False)]: if (cc[i] == c[i]) != t:
if p2.x != 2.3 or p2.y != 2.4 or p2.on_curve or not p2.selected or p2.name != 'test': raise ValueError("Bad point values") if p2 != (2.3, 2.4): raise ValueError("Bad point comparison") if p2 != p: raise ValueError("Bad point comparison") # contour ptl = [(0, 0), (1, 1, False), (2, 2, False), (3, 3), (4, 4), (5, 5, False), (6, 6, False), (7, 7), (8, 8, False), (9, 0, False)] ptl2 = [(4.2, 4.2), (4.5, 4.5), (4.7, 4.7)] c = f.contour() if len(c) != 0 or c.is_quadratic: raise ValueError("Bad contour values") c = f.contour(True) # Set quadratic if len(c) != 0 or not c.is_quadratic: raise ValueError("Bad contour values") c.is_quadratic = False if c.is_quadratic: raise ValueError("Bad contour values") for pt in ptl: c.insertPoint(pt) c.closed = True if len(c) != 10:
p2 = p.dup() if p2.x != 2.3 or p2.y != 2.4 or p2.on_curve or not p2.selected or p2.name != 'test': raise ValueError("Bad point values" ) if p2 != (2.3,2.4): raise ValueError("Bad point comparison" ) if p2 != p: raise ValueError("Bad point comparison" ) # contour ptl = [(0,0),(1,1,False),(2,2,False),(3,3),(4,4),(5,5,False),(6,6,False),(7,7),(8,8,False),(9,0,False)] ptl2 = [(4.2,4.2),(4.5,4.5),(4.7,4.7)] c = f.contour() if len(c) != 0 or c.is_quadratic: raise ValueError("Bad contour values" ) c = f.contour(True) # Set quadratic if len(c) != 0 or not c.is_quadratic: raise ValueError("Bad contour values" ) c.is_quadratic = False if c.is_quadratic: raise ValueError("Bad contour values" ) for pt in ptl: c.insertPoint(pt) c.closed = True; if len(c) != 10:
#!/usr/local/bin/fontforge import fontforge Font = fontforge.open("VexillaNationum.sfd") for Glyph in Font.glyphs(): print Glyph.glyphname if Glyph.isWorthOutputting(): for Contour in Glyph.foreground: if len(Contour) == 1: X = Contour[0].x; Y = Contour[0].y Radius = 12 MagnPnct = fontforge.contour() MagnPnct += fontforge.point(X+Radius,Y+Radius,False) MagnPnct += fontforge.point(X+Radius,Y,True) MagnPnct += fontforge.point(X+Radius,Y-Radius,False) MagnPnct += fontforge.point(X+Radius,Y-Radius,False) MagnPnct += fontforge.point(X,Y-Radius,True) MagnPnct += fontforge.point(X-Radius,Y-Radius,False) MagnPnct += fontforge.point(X-Radius,Y-Radius,False) MagnPnct += fontforge.point(X-Radius,Y,True) MagnPnct += fontforge.point(X-Radius,Y+Radius,False) MagnPnct += fontforge.point(X-Radius,Y+Radius,False) MagnPnct += fontforge.point(X,Y+Radius,True) MagnPnct += fontforge.point(X+Radius,Y+Radius,False) MagnPnct.closed = True Glyph.foreground += MagnPnct Glyph.stroke("circular",16,"round","miter",()) Glyph.removeOverlap() Glyph.simplify(0,("mergelines",),0,0,0) Font.strokedfont = False Font.generate("VexillaNationum.ttf")
def selectExistAll(font): font.selection.none() for glyphName in font: if font[glyphName].isWorthOutputting() == True: font.selection.select(("more",), glyphName) ######################################## # bold ######################################## print print "Open " + srcfont fSrc = fontforge.open( srcfont ) contour = fontforge.contour() contour.moveTo(-generate_horizontal, generate_vertical) contour.lineTo( generate_horizontal, generate_vertical) contour.lineTo( generate_horizontal, -generate_vertical) contour.lineTo(-generate_horizontal, -generate_vertical) contour.lineTo(-generate_horizontal, generate_vertical) contour.closed = True # modify print "bold" # 拡大 for glyphName in fSrc: if fSrc[glyphName].isWorthOutputting() == True: if fSrc[glyphName].unicode < 10000: print "bold : code 0u" + ('%x' % fSrc[glyphName].unicode) + "(" + str(fSrc[glyphName].unicode) + ")" + ", " + fSrc[glyphName].glyphname fSrc[glyphName].stroke("polygonal", contour, ('removeinternal'))
def selectExistAll(font): font.selection.none() for glyphName in font: if font[glyphName].isWorthOutputting() == True: font.selection.select(("more", ), glyphName) ######################################## # bold ######################################## print print "Open " + srcfont fSrc = fontforge.open(srcfont) contour = fontforge.contour() contour.moveTo(-generate_horizontal, generate_vertical) contour.lineTo(generate_horizontal, generate_vertical) contour.lineTo(generate_horizontal, -generate_vertical) contour.lineTo(-generate_horizontal, -generate_vertical) contour.lineTo(-generate_horizontal, generate_vertical) contour.closed = True # modify print "bold" # 拡大 for glyphName in fSrc: if fSrc[glyphName].isWorthOutputting() == True: if fSrc[glyphName].unicode < 10000: print "bold : code 0u" + ( '%x' % fSrc[glyphName].unicode) + "(" + str(
# Round-trip point selection tests. import copy import fontforge as ff import pickle c0 = [(293.0,48.0,1), (291.0,48.0,1), (271.0,32.0,1), (227.0,-2.0,0), (196.8,-10.0,0), (162.0,-10.0,1), (92.0,-10.0,0), (36.0,16.0,0), (36.0,98.0,1), (36.0,166.0,0), (105.0,219.0,0), (201.0,243.0,1), (287.0,264.0,1), (290.0,265.0,0), (293.0,269.0,0), (293.0,276.0,1), (293.0,389.0,0), (246.0,406.0,0), (212.0,406.0,1), (174.0,406.0,0), (132.0,395.0,0), (132.0,364.0,1), (132.0,353.0,0), (133.0,347.0,0), (134.0,344.0,1), (136.0,340.0,0), (137.0,333.0,0), (137.0,326.0,1), (137.0,313.0,0), (119.0,292.0,0), (90.0,292.0,1), (67.0,292.0,0), (55.0,304.0,0), (55.0,328.0,1), (55.0,385.0,0), (138.0,439.0,0), (220.0,439.0,1), (293.0,439.0,0), (371.0,412.0,0), (371.0,270.0,1), (371.0,123.0,1), (371.0,77.0,0), (372.0,38.0,0), (401.0,38.0,1), (413.7,38.0,0), (430.5,47.8,0), (438.0,54.0,1), (449.3,47.7,0), (453.3,39.3,0), (455.0,27.0,1), (434.3,7.0,0), (398.3,-10.0,0), (360.0,-10.0,1), (309.6,-10.0,0), (299.0,17.0,0)] f = ff.font() g = f.createMappedChar('a') l = ff.layer() c = ff.contour() # Cubic c[:] = c0 c.closed = True l += c for (i,p) in enumerate(l[0]): if i % 5 == 0: p.selected = True g.layers[1] = l l = g.layers[1] for (i,p) in enumerate(l[0]): if (i % 5 == 0 and not p.selected) or (i % 5 != 0 and p.selected): raise ValueError("Round trip of layer changed selection status")
glyph.background.is_quadratic = False pen = glyph.glyphPen() pen.moveTo((1, 1)) pen.closePath() del pen # crash if (auto)destroyed after font.close()... font.generate('a.ttf', flags=('PfEd-background')) font.close() font = fontforge.open('a.ttf') glyph = font[0x41] assert len(glyph.foreground) == 1, 'Foreground contains a contour' assert len(glyph.background) == 1, 'Background contains a contour' fgc = fontforge.contour(True) fgc.closed = True fgc[:] = ((0, 0), (1, 1), (1, 0)) # contour comparator is inexact, see PyFFContour_docompare / SSsCompare assert glyph.foreground[ 0] == fgc, 'Foreground contour matches expected contour' assert list(glyph.foreground[0]) == list( fgc), 'Foreground contour points matches expected contour points' bgc = fontforge.contour(False) bgc.closed = True bgc[:] = ((1, 1), ) assert glyph.background[ 0] == bgc, 'Background contour matches expected contour' assert list(glyph.background[0]) == list( bgc), 'Foreground contour points matches expected contour points'