├── AssignFontLayer └── AssignFontLayer.py ├── AssignKerningGroups └── AssignKerningGroups.py ├── BlackSurfaceBenchmark ├── CalculateBlackSurfaceBenchmark.py └── glyph_a.txt ├── ConvertSegments ├── ConvertToCurves.py └── ConvertToLines.py ├── CopyToMask └── CopyToMask.py ├── CreateEncoding └── CreateEncoding.py ├── ExpandKerning └── ExpandKerning.py ├── GenerateFont └── GenerateFont.py ├── GlyphIntegrityCheck └── GlyphIntegrityCheck.py ├── Interpolate └── Interpolate.py ├── MakeAccents └── MakeAccents.py ├── MakeFractions └── MakeFractions.py ├── README.md ├── StemsAnalyser └── StemsAnalyser.roboFontExt │ ├── info.plist │ └── lib │ ├── .DS_Store │ ├── StemsAnalyser.py │ └── StemsAnalyserModule.py └── Tests ├── Convert2Quadratic.py └── copyFontInfos.py /AssignFontLayer/AssignFontLayer.py: -------------------------------------------------------------------------------- 1 | from vanilla import * 2 | import string, sys 3 | 4 | 5 | af = AllFonts() 6 | f = CurrentFont() 7 | 8 | 9 | def createFontList(): 10 | fontList = [] 11 | for f in af: 12 | if f.info.familyName and f.info.styleName: 13 | fontList.append(f.info.familyName + " " + f.info.styleName) 14 | else: 15 | return 16 | return fontList 17 | 18 | class AssignFontLayerWindow(object): 19 | 20 | def __init__(self): 21 | self.w = Window((200, 300), "Assign Font Layer") 22 | self.w.textBoxSource = TextBox((10, 10, -10, 30), "Source Font:") 23 | self.w.popUpButtonSource = PopUpButton((10, 30, -10, 30), fontList, callback=self.popUpButtonSourceCallback, sizeStyle = "regular") 24 | 25 | self.w.textBoxTarget = TextBox((10, 70, -10, 30), "Target Font:") 26 | self.w.popUpButtonTarget = PopUpButton((10, 90, -10, 30), fontList, callback=self.popUpButtonTargetCallback, sizeStyle = "regular") 27 | 28 | self.w.textBox = TextBox((10, 130, -10, 30), "Layer Name in Target Font:") 29 | self.w.editText = EditText((10, 160, -10, 30), 30 | callback=self.editTextCallback) 31 | 32 | self.fontSourceName = fontList[0] 33 | self.fontTargetName = fontList[0] 34 | self.fontSourceIndex = 0 35 | self.fontTargetIndex = 0 36 | 37 | self.fontSourceList = self.w.popUpButtonSource.getItems() 38 | self.fontTargetList = self.w.popUpButtonTarget.getItems() 39 | 40 | self.w.buttonOK = Button((10, -30, 90, -10), "OK", 41 | callback=self.buttonOKCallback) 42 | self.w.buttonCancel = Button((110, -30, -10, -10), "Cancel", 43 | callback=self.buttonCancelCallback) 44 | self.layerName = "untitled_layer" 45 | self.w.editText.set(self.layerName) 46 | self.w.center() 47 | self.w.open() 48 | 49 | def buttonOKCallback(self, sender): 50 | #print "Ok" 51 | 52 | sourceFont = af[self.fontSourceIndex] 53 | targetFont = af[self.fontTargetIndex] 54 | #print "Source Font:", sourceFont 55 | #print "Target Font:", targetFont 56 | #print "New Layer Name:", self.layerName 57 | 58 | #get the first glyph's name 59 | firstGlyphName = targetFont.keys()[0] 60 | #create a new layer with specified layerName 61 | targetFont[firstGlyphName].getLayer(self.layerName) 62 | #parse the target font's glyphs 63 | for gT in targetFont: 64 | #parse the source font's glyphs 65 | for gS in sourceFont: 66 | #if their names match, I want the targetLayer to be a copy of the sourceLayer 67 | if gT.name == gS.name: 68 | sourceLayer = gS.getLayer("foreground") 69 | targetLayer = gT.getLayer(self.layerName) 70 | #clear contours if any 71 | targetLayer.clear() 72 | targetWidth = gT.width 73 | gT.flipLayers("foreground", self.layerName) 74 | targetFont[gT.name] = gS.copy() 75 | targetFont[gT.name].width = targetWidth 76 | gT.flipLayers("foreground", self.layerName) 77 | self.w.close() 78 | 79 | def buttonCancelCallback(self, sender): 80 | #print "Cancel" 81 | self.w.close() 82 | 83 | def popUpButtonSourceCallback(self, sender): 84 | #print "pop up button selection!", sender.get() 85 | 86 | self.fontSourceIndex = sender.get() 87 | self.fontSourceName = self.fontSourceList[sender.get()] 88 | #print self.fontName 89 | 90 | def popUpButtonTargetCallback(self, sender): 91 | #print "pop up button selection!", sender.get() 92 | 93 | self.fontTargetIndex = sender.get() 94 | self.fontTargetName = self.fontTargetList[sender.get()] 95 | #print self.fontName 96 | 97 | def editTextCallback(self, sender): 98 | 99 | #layerName = sender.get().title() 100 | layerName = '' 101 | layerNameList = sender.get().split(" ") 102 | for i in range(len(layerNameList)): 103 | layerName += layerNameList[i] 104 | if i < len(layerNameList)-1: 105 | layerName += '_' 106 | self.layerName = layerName 107 | 108 | fontList = createFontList() 109 | if fontList: 110 | AssignFontLayerWindow() 111 | else: 112 | print 'All open fonts must have familyName and styleName' -------------------------------------------------------------------------------- /AssignKerningGroups/AssignKerningGroups.py: -------------------------------------------------------------------------------- 1 | f = CurrentFont() 2 | kerning = f.kerning 3 | newKerning = {} 4 | 5 | def assignGroups(f): 6 | groupsList = [] 7 | leadersList = [] 8 | for i in f.groups.keys(): 9 | leader = f.groups[i][0] 10 | leadersList.append(leader) 11 | groupsList.append(i) 12 | print len(groupsList) 13 | print len(leadersList) 14 | 15 | for pair, value in kerning.items(): 16 | left = pair[0] 17 | right = pair[1] 18 | for i in range(len(leadersList)): 19 | if left == leadersList[i] and groupsList[i][-5:] != 'RIGHT': 20 | c_leftKey = groupsList[i] 21 | for j in range(len(leadersList)): 22 | if right == leadersList[j] and groupsList[j][-4:] !='LEFT': 23 | c_rightKey = groupsList[j] 24 | #print c_leftKey, c_rightKey, value 25 | newKerning[(c_leftKey, c_rightKey)] = value 26 | 27 | f.kerning.clear() 28 | f.kerning.update(newKerning) 29 | 30 | assignGroups(f) 31 | #for pair, value in f.kerning.keys(): 32 | # if pair[0] == '@_LAT_A_UC': 33 | # print pair, value 34 | -------------------------------------------------------------------------------- /BlackSurfaceBenchmark/CalculateBlackSurfaceBenchmark.py: -------------------------------------------------------------------------------- 1 | import freetype 2 | import os 3 | import time 4 | 5 | 6 | f = CurrentFont() 7 | g = CurrentGlyph() 8 | 9 | def calculateBlackRaster(g): 10 | if g == None: 11 | print 'selcet a glyph first' 12 | return 13 | 14 | root = os.path.split(f.path)[0] 15 | tail = 'Temp.ttf' 16 | fulltempfontpath = os.path.join(root, tail) 17 | 18 | f.generate(fulltempfontpath,'ttf', decompose = False, checkOutlines = False, autohint = False, releaseMode = False, glyphOrder=None, progressBar = None ) 19 | 20 | start = time.time() 21 | 22 | face = freetype.Face(fulltempfontpath) 23 | face.set_pixel_sizes(1000, 1000) 24 | face.load_char(g.name, freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO ) 25 | 26 | surface = len(face.glyph.bitmap.buffer) 27 | black = 0 28 | for pixel in face.glyph.bitmap.buffer: 29 | if pixel == 255: 30 | black += 1 31 | 32 | print "with FreeType:" 33 | print "finished in %f seconds" % (time.time() - start) 34 | print 'black:', (black/surface)*100, '%' 35 | 36 | def calculateBlackContains(g): 37 | if g == None: 38 | print 'selcet a glyph first' 39 | return 40 | path = g.naked().getRepresentation("defconAppKit.NSBezierPath") 41 | xMin, yMin, xMax, yMax = g.box 42 | xMin = int(round(xMin)) 43 | yMin = int(round(yMin)) 44 | xMax= int(round(xMax)) 45 | yMax = int(round(yMax)) 46 | surface = (xMax - xMin) * (yMax - yMin) 47 | 48 | start = time.time() 49 | black = 0 50 | for x in range(xMin, xMax): 51 | for y in range(yMin, yMax): 52 | if path.containsPoint_((x,y)): 53 | black += 1 54 | 55 | print "with containsPoint:" 56 | print "finished in %f seconds" % (time.time() - start) 57 | print 'black:', (black/surface)*100, '%' 58 | 59 | calculateBlackRaster(g) 60 | calculateBlackContains(g) -------------------------------------------------------------------------------- /BlackSurfaceBenchmark/glyph_a.txt: -------------------------------------------------------------------------------- 1 | with FreeType: 2 | finished in 0.037723 seconds 3 | black: 66.2745098039 % 4 | with containsPoint: 5 | finished in 1.036176 seconds 6 | black: 70.2718454685 % 7 | -------------------------------------------------------------------------------- /ConvertSegments/ConvertToCurves.py: -------------------------------------------------------------------------------- 1 | def computeInsertAttributes(): 2 | g = CurrentGlyph() 3 | # SAM SAYS: j'ai viré x_list et y_list car non utilisés 4 | insertAttributes = [] 5 | for c_index in range(len(g.contours)): 6 | c = g.contours[c_index] 7 | for s_index in range(len(c.segments)): 8 | s = c.segments[s_index] 9 | #print s.type 10 | if not s.selected: 11 | continue 12 | if s.type == "line": 13 | endPoint = s[0] 14 | prev = c.segments[s_index - 1] 15 | if prev.type == 'curve': 16 | startPoint = prev[2] 17 | elif prev.type in ['line', 'move']: 18 | startPoint = prev[0] 19 | else: # SAM SAYS: ai ajouté ce warning: 20 | print("WARNING: I don't know this kind of segment: "+prev.type) 21 | continue 22 | 23 | third_x = int((endPoint.x - startPoint.x) / 3) 24 | third_y = int((endPoint.y - startPoint.y) / 3) 25 | 26 | insertAttributes.append( 27 | ( c_index, 28 | s_index, 29 | (startPoint.x + third_x, startPoint.y + third_y), 30 | (endPoint.x - third_x, endPoint.y - third_y), 31 | (endPoint.x, endPoint.y) 32 | ) 33 | ) 34 | return insertAttributes 35 | 36 | def convertToCurve(): 37 | g = CurrentGlyph() 38 | # SAM SAYS: je test la négation et 'return', ça permet de ne pas avoir à indenter ce qui suit. 39 | # (compare avec ton test initial) 40 | if (not g) or g.selection == []: 41 | return 42 | g.prepareUndo() 43 | for i in computeInsertAttributes(): 44 | # SAM SAYS: j'ai changé 'i' en un 'tuple' (en l'occurence, un quintuplet) plutôt qu'une liste, 45 | # et j'extrais les cinque valeurs d'un coup: 46 | c_idx, s_idx, p1, p2, p3 = i 47 | g.contours[c_idx].insertSegment(s_idx, 'curve', (p1, p2, p3), False) 48 | #print s_idx, len(g.contours[c_idx].segments) 49 | # SAM SAYS: pas besoin du cas s_idx == 0. Par contre, je pense que ci-dessous, il faut '- 1' et pas '- 2' 50 | if s_idx == len(g.contours[c_idx].segments) - 2: 51 | #print 'last segment' 52 | g.contours[c_idx].removeSegment(0) 53 | else: 54 | g.contours[c_idx].removeSegment(s_idx+1) 55 | g.update() 56 | 57 | convertToCurve() 58 | -------------------------------------------------------------------------------- /ConvertSegments/ConvertToLines.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def convertToLine(): 4 | g = CurrentGlyph() 5 | if g and g.selection != []: 6 | g.prepareUndo() 7 | a_list_x = [] 8 | a_list_y = [] 9 | insertAttributes = [] 10 | 11 | for c_index in range(len(g.contours)): 12 | c = g.contours[c_index] 13 | for s_index in range(len(c.segments)): 14 | s = c.segments[s_index] 15 | if s.selected and s.type == "curve": 16 | s.type = "line" 17 | # #print 'curve' 18 | # endPoint = c.segments[s_index][2] 19 | # if c.segments[s_index - 1].type == 'curve': 20 | # startPoint = c.segments[s_index - 1][2] 21 | # elif c.segments[s_index - 1].type == 'line': 22 | # startPoint = c.segments[s_index - 1][0] 23 | # #print startPoint, endPoint 24 | 25 | # insertAttributes.append([c_index, s_index, (endPoint.x, endPoint.y)]) 26 | 27 | #for i in insertAttributes: 28 | # if i[1] == 0: 29 | # #print 'first segment' 30 | # if g.contours[i[0]][1].type == 'curve': 31 | # #print 'next is curve' 32 | # g.contours[i[0]].insertSegment(i[1], 'line', [i[2]], False) 33 | # g.contours[i[0]][i[1]+1].points[0].x = g.contours[i[0]][i[1] + 2].points[0].x 34 | # g.contours[i[0]][i[1]+1].points[0].y = g.contours[i[0]][i[1] + 2].points[0].y 35 | # g.contours[i[0]].removeSegment(i[1]+1) 36 | # elif g.contours[i[0]][1].type == 'line': 37 | # #print 'next is line' 38 | # g.contours[i[0]].insertSegment(i[1], 'line', [i[2]], False) 39 | # g.contours[i[0]][i[1]+1].points[0].x = g.contours[i[0]][i[1] + 2].points[0].x 40 | # g.contours[i[0]][i[1]+1].points[0].y = g.contours[i[0]][i[1] + 2].points[0].y 41 | 42 | # g.contours[i[0]][i[1]+1].points[1].x = g.contours[i[0]][i[1] + 2].points[0].x 43 | # g.contours[i[0]][i[1]+1].points[1].y = g.contours[i[0]][i[1] + 2].points[0].y 44 | 45 | # g.contours[i[0]].removeSegment(i[1]+1) 46 | # elif i[1] == len(g.contours[i[0]].segments) - 1: 47 | # #print 'last segment' 48 | # if g.contours[i[0]][0].type == 'curve': 49 | # #print 'next is curve' 50 | # g.contours[i[0]].insertSegment(i[1], 'line', [i[2]], False) 51 | # g.contours[i[0]][i[1]+1].points[0].x = g.contours[i[0]][0].points[0].x 52 | # g.contours[i[0]][i[1]+1].points[0].y = g.contours[i[0]][0].points[0].y 53 | # g.contours[i[0]].removeSegment(i[1]+1) 54 | # elif g.contours[i[0]][0].type == 'line': 55 | # #print 'next is line' 56 | # g.contours[i[0]].insertSegment(i[1], 'line', [i[2]], False) 57 | # g.contours[i[0]][i[1]+1].points[0].x = g.contours[i[0]][0].points[0].x 58 | # g.contours[i[0]][i[1]+1].points[0].y = g.contours[i[0]][0].points[0].y 59 | 60 | # g.contours[i[0]][i[1]+1].points[1].x = g.contours[i[0]][0].points[0].x 61 | # g.contours[i[0]][i[1]+1].points[1].y = g.contours[i[0]][0].points[0].y 62 | 63 | # g.contours[i[0]].removeSegment(i[1]+1) 64 | # else: 65 | # if g.contours[i[0]][i[1]+1].type == 'curve': 66 | # #print 'next is curve' 67 | # g.contours[i[0]].insertSegment(i[1], 'line', [i[2]], False) 68 | # g.contours[i[0]][i[1]+1].points[0].x = g.contours[i[0]][i[1] + 2].points[0].x 69 | # g.contours[i[0]][i[1]+1].points[0].y = g.contours[i[0]][i[1] + 2].points[0].y 70 | # g.contours[i[0]].removeSegment(i[1]+1) 71 | # if g.contours[i[0]][i[1]+1].type == 'line': 72 | # #print 'next is line' 73 | # g.contours[i[0]].insertSegment(i[1], 'line', [i[2]], False) 74 | # g.contours[i[0]][i[1]+1].points[0].x = g.contours[i[0]][i[1] + 2].points[0].x 75 | # g.contours[i[0]][i[1]+1].points[0].y = g.contours[i[0]][i[1] + 2].points[0].y 76 | 77 | # g.contours[i[0]][i[1]+1].points[1].x = g.contours[i[0]][i[1] + 2].points[0].x 78 | # g.contours[i[0]][i[1]+1].points[1].y = g.contours[i[0]][i[1] + 2].points[0].y 79 | 80 | # g.contours[i[0]].removeSegment(i[1]+1) 81 | 82 | g.update() 83 | 84 | 85 | convertToLine() 86 | 87 | -------------------------------------------------------------------------------- /CopyToMask/CopyToMask.py: -------------------------------------------------------------------------------- 1 | 2 | g = CurrentGlyph() 3 | 4 | mask = g.getLayer("mask") 5 | mask.prepareUndo() 6 | g.prepareUndo() 7 | 8 | mask.clear() 9 | g.copyToLayer("mask") 10 | mask.update() 11 | 12 | g.update() 13 | -------------------------------------------------------------------------------- /CreateEncoding/CreateEncoding.py: -------------------------------------------------------------------------------- 1 | from vanilla import * 2 | from defconAppKit.windows.baseWindow import BaseWindowController 3 | 4 | encodingL = [ 5 | '.notdef', 6 | '.null', 7 | 'CR', 8 | 'space', 9 | 'uni00A0', 10 | 'A', 11 | 'B', 12 | 'C', 13 | 'D', 14 | 'E', 15 | 'F', 16 | 'G', 17 | 'H', 18 | 'I', 19 | 'J', 20 | 'K', 21 | 'L', 22 | 'M', 23 | 'N', 24 | 'O', 25 | 'P', 26 | 'Q', 27 | 'R', 28 | 'S', 29 | 'T', 30 | 'U', 31 | 'V', 32 | 'W', 33 | 'X', 34 | 'Y', 35 | 'Z', 36 | 'AE', 37 | 'OE', 38 | 'Lslash', 39 | 'Oslash', 40 | 'Eth', 41 | 'Thorn', 42 | 43 | 'a', 44 | 'b', 45 | 'c', 46 | 'd', 47 | 'e', 48 | 'f', 49 | 'g', 50 | 'h', 51 | 'i', 52 | 'j', 53 | 'k', 54 | 'l', 55 | 'm', 56 | 'n', 57 | 'o', 58 | 'p', 59 | 'q', 60 | 'r', 61 | 's', 62 | 't', 63 | 'u', 64 | 'v', 65 | 'w', 66 | 'x', 67 | 'y', 68 | 'z', 69 | 'ae', 70 | 'oe', 71 | 'lslash', 72 | 'oslash', 73 | 'eth', 74 | 'thorn', 75 | 'germandbls', 76 | 'dotlessi', 77 | 'dotlessj', 78 | 79 | 'fi', 80 | 'fl', 81 | 'f_f', 82 | 'f_f_i', 83 | 'f_f_l', 84 | 85 | 'f_t', 86 | 'f_b', 87 | 'f_f_b', 88 | 'f_h', 89 | 'f_f_h', 90 | 'f_k', 91 | 'f_f_k', 92 | 'f_j', 93 | 'f_f_j', 94 | 'f_f_t', 95 | 'c_t', 96 | 's_p', 97 | 's_t', 98 | 99 | 'a.sc', 100 | 'b.sc', 101 | 'c.sc', 102 | 'd.sc', 103 | 'e.sc', 104 | 'f.sc', 105 | 'g.sc', 106 | 'h.sc', 107 | 'i.sc', 108 | 'j.sc', 109 | 'k.sc', 110 | 'l.sc', 111 | 'm.sc', 112 | 'n.sc', 113 | 'o.sc', 114 | 'p.sc', 115 | 'q.sc', 116 | 'r.sc', 117 | 's.sc', 118 | 't.sc', 119 | 'u.sc', 120 | 'v.sc', 121 | 'w.sc', 122 | 'x.sc', 123 | 'y.sc', 124 | 'z.sc', 125 | 'ae.sc', 126 | 'oe.sc', 127 | 'lslash.sc', 128 | 'oslash.sc', 129 | 'eth.sc', 130 | 'thorn.sc', 131 | 'germandbls.sc', 132 | 'dotlessi.sc', 133 | 'dotlessj.sc', 134 | 135 | 'ampersand.sc', 136 | 'exclam.sc', 137 | 'question.sc', 138 | 'exclamdown.sc', 139 | 'questiondown.sc', 140 | 'parenleft.sc', 141 | 'parenright.sc', 142 | 'braceleft.sc', 143 | 'braceright.sc', 144 | 'bracketleft.sc', 145 | 'bracketright.sc', 146 | 'hyphen.sc', 147 | 'quoteleft.sc', 148 | 'quotedblleft.sc', 149 | 'quoteright.sc', 150 | 'quotedblright.sc', 151 | 'quotesingle.sc', 152 | 'quotedbl.sc', 153 | 154 | 'Aacute', 155 | 'Acircumflex', 156 | 'Adieresis', 157 | 'Agrave', 158 | 'Aring', 159 | 'Atilde', 160 | 'Abreve', 161 | 'Amacron', 162 | 'Aogonek', 163 | 'Ccedilla', 164 | 'Cacute', 165 | 'Ccaron', 166 | 'Ccircumflex', 167 | 'Cdotaccent', 168 | 'Dcaron', 169 | 'Dcroat', 170 | 'Eacute', 171 | 'Ecircumflex', 172 | 'Edieresis', 173 | 'Egrave', 174 | 'Ebreve', 175 | 'Ecaron', 176 | 'Edotaccent', 177 | 'Emacron', 178 | 'Eogonek', 179 | 'Gbreve', 180 | 'Gcircumflex', 181 | 'Gcommaaccent', 182 | 'Gdotaccent', 183 | 'Hbar', 184 | 'Hcircumflex', 185 | 'Iacute', 186 | 'Icircumflex', 187 | 'Idieresis', 188 | 'Igrave', 189 | 'Ibreve', 190 | 'Idotaccent', 191 | 'Imacron', 192 | 'Iogonek', 193 | 'Itilde', 194 | 'Jcircumflex', 195 | 'IJ', 196 | 'Kcommaaccent', 197 | 'Lacute', 198 | 'Lcaron', 199 | 'Lcommaaccent', 200 | 'Ldot', 201 | 'Ntilde', 202 | 'Nacute', 203 | 'Ncaron', 204 | 'Ncommaaccent', 205 | 'Oacute', 206 | 'Ocircumflex', 207 | 'Odieresis', 208 | 'Ograve', 209 | 'Otilde', 210 | 'Obreve', 211 | 'Ohungarumlaut', 212 | 'Omacron', 213 | 'Racute', 214 | 'Rcaron', 215 | 'Rcommaaccent', 216 | 'Scaron', 217 | 'Sacute', 218 | 'Scedilla', 219 | 'Scircumflex', 220 | 'uni0218', 221 | 'Tbar', 222 | 'Tcaron', 223 | 'uni0162', 224 | 'uni021A', 225 | 'Uacute', 226 | 'Ucircumflex', 227 | 'Udieresis', 228 | 'Ugrave', 229 | 'Ubreve', 230 | 'Uhungarumlaut', 231 | 'Umacron', 232 | 'Uogonek', 233 | 'Uring', 234 | 'Utilde', 235 | 'Wacute', 236 | 'Wcircumflex', 237 | 'Wdieresis', 238 | 'Wgrave', 239 | 'Yacute', 240 | 'Ydieresis', 241 | 'Ycircumflex', 242 | 'Ygrave', 243 | 'Zcaron', 244 | 'Zacute', 245 | 'Zdotaccent', 246 | 247 | 'aacute', 248 | 'acircumflex', 249 | 'adieresis', 250 | 'agrave', 251 | 'aring', 252 | 'atilde', 253 | 'abreve', 254 | 'amacron', 255 | 'aogonek', 256 | 'ccedilla', 257 | 'cacute', 258 | 'ccaron', 259 | 'ccircumflex', 260 | 'cdotaccent', 261 | 'dcaron', 262 | 'dcroat', 263 | 'eacute', 264 | 'ecircumflex', 265 | 'edieresis', 266 | 'egrave', 267 | 'ebreve', 268 | 'ecaron', 269 | 'edotaccent', 270 | 'emacron', 271 | 'eogonek', 272 | 'gbreve', 273 | 'gcircumflex', 274 | 'gcommaaccent', 275 | 'gdotaccent', 276 | 'hbar', 277 | 'hcircumflex', 278 | 'iacute', 279 | 'icircumflex', 280 | 'idieresis', 281 | 'igrave', 282 | 'ibreve', 283 | 'i.dot', 284 | 'imacron', 285 | 'iogonek', 286 | 'itilde', 287 | 'jcircumflex', 288 | 'ij', 289 | 'kcommaaccent', 290 | 'lacute', 291 | 'lcaron', 292 | 'lcommaaccent', 293 | 'ldot', 294 | 'ntilde', 295 | 'nacute', 296 | 'ncaron', 297 | 'ncommaaccent', 298 | 'oacute', 299 | 'ocircumflex', 300 | 'odieresis', 301 | 'ograve', 302 | 'otilde', 303 | 'obreve', 304 | 'ohungarumlaut', 305 | 'omacron', 306 | 'racute', 307 | 'rcaron', 308 | 'rcommaaccent', 309 | 'scaron', 310 | 'sacute', 311 | 'scedilla', 312 | 'scircumflex', 313 | 'uni0219', 314 | 'tbar', 315 | 'tcaron', 316 | 'uni0163', 317 | 'uni021B', 318 | 'uacute', 319 | 'ucircumflex', 320 | 'udieresis', 321 | 'ugrave', 322 | 'ubreve', 323 | 'uhungarumlaut', 324 | 'umacron', 325 | 'uogonek', 326 | 'uring', 327 | 'utilde', 328 | 'wacute', 329 | 'wcircumflex', 330 | 'wdieresis', 331 | 'wgrave', 332 | 'yacute', 333 | 'ydieresis', 334 | 'ycircumflex', 335 | 'ygrave', 336 | 'zcaron', 337 | 'zacute', 338 | 'zdotaccent', 339 | 340 | 'aacute.sc', 341 | 'acircumflex.sc', 342 | 'adieresis.sc', 343 | 'agrave.sc', 344 | 'aring.sc', 345 | 'atilde.sc', 346 | 'abreve.sc', 347 | 'amacron.sc', 348 | 'aogonek.sc', 349 | 'ccedilla.sc', 350 | 'cacute.sc', 351 | 'ccaron.sc', 352 | 'ccircumflex.sc', 353 | 'cdotaccent.sc', 354 | 'dcaron.sc', 355 | 'dcroat.sc', 356 | 'eacute.sc', 357 | 'ecircumflex.sc', 358 | 'edieresis.sc', 359 | 'egrave.sc', 360 | 'ebreve.sc', 361 | 'ecaron.sc', 362 | 'edotaccent.sc', 363 | 'emacron.sc', 364 | 'eogonek.sc', 365 | 'gbreve.sc', 366 | 'gcircumflex.sc', 367 | 'gcommaaccent.sc', 368 | 'gdotaccent.sc', 369 | 'hbar.sc', 370 | 'hcircumflex.sc', 371 | 'iacute.sc', 372 | 'icircumflex.sc', 373 | 'idieresis.sc', 374 | 'igrave.sc', 375 | 'ibreve.sc', 376 | 'i.dot.sc', 377 | 'imacron.sc', 378 | 'iogonek.sc', 379 | 'itilde.sc', 380 | 'jcircumflex.sc', 381 | 'ij.sc', 382 | 'kcommaaccent.sc', 383 | 'lacute.sc', 384 | 'lcaron.sc', 385 | 'lcommaaccent.sc', 386 | 'ldot.sc', 387 | 'ntilde.sc', 388 | 'nacute.sc', 389 | 'ncaron.sc', 390 | 'ncommaaccent.sc', 391 | 'oacute.sc', 392 | 'ocircumflex.sc', 393 | 'odieresis.sc', 394 | 'ograve.sc', 395 | 'otilde.sc', 396 | 'obreve.sc', 397 | 'ohungarumlaut.sc', 398 | 'omacron.sc', 399 | 'racute.sc', 400 | 'rcaron.sc', 401 | 'rcommaaccent.sc', 402 | 'scaron.sc', 403 | 'sacute.sc', 404 | 'scedilla.sc', 405 | 'scircumflex.sc', 406 | 'uni0219.sc', 407 | 'tbar.sc', 408 | 'tcaron.sc', 409 | 'uni0163.sc', 410 | 'uni021B.sc', 411 | 'uacute.sc', 412 | 'ucircumflex.sc', 413 | 'udieresis.sc', 414 | 'ugrave.sc', 415 | 'ubreve.sc', 416 | 'uhungarumlaut.sc', 417 | 'umacron.sc', 418 | 'uogonek.sc', 419 | 'uring.sc', 420 | 'utilde.sc', 421 | 'wacute.sc', 422 | 'wcircumflex.sc', 423 | 'wdieresis.sc', 424 | 'wgrave.sc', 425 | 'yacute.sc', 426 | 'ydieresis.sc', 427 | 'ycircumflex.sc', 428 | 'ygrave.sc', 429 | 'zcaron.sc', 430 | 'zacute.sc', 431 | 'zdotaccent.sc', 432 | 433 | 'acute', 434 | 'grave', 435 | 'circumflex', 436 | 'caron', 437 | 'tilde', 438 | 'dieresis', 439 | 'ring', 440 | 'cedilla', 441 | 442 | 'hungarumlaut', 443 | 'breve', 444 | 'macron', 445 | 'dotaccent', 446 | 'periodcentered', 447 | 'ogonek', 448 | 'commaaccent', 449 | 450 | 'caron.alt', 451 | 'revcommaaccent', 452 | 453 | 'acute.cap', 454 | 'grave.cap', 455 | 'circumflex.cap', 456 | 'caron.cap', 457 | 'tilde.cap', 458 | 'dieresis.cap', 459 | 'ring.cap', 460 | 'cedilla.cap', 461 | 462 | 'hungarumlaut.cap', 463 | 'breve.cap', 464 | 'macron.cap', 465 | 'dotaccent.cap', 466 | 'ogonek.cap', 467 | 'commaaccent.cap', 468 | 'caron.alt.cap', 469 | 470 | 'acute.sc', 471 | 'grave.sc', 472 | 'circumflex.sc', 473 | 'caron.sc', 474 | 'tilde.sc', 475 | 'dieresis.sc', 476 | 'ring.sc', 477 | 'cedilla.sc', 478 | 479 | 'hungarumlaut.sc', 480 | 'breve.sc', 481 | 'macron.sc', 482 | 'dotaccent.sc', 483 | 'ogonek.sc', 484 | 'commaaccent.sc', 485 | 'caron.alt.sc', 486 | 487 | 'period', 488 | 'comma', 489 | 'colon', 490 | 'semicolon', 491 | 'ellipsis', 492 | 'question', 493 | 'exclam', 494 | 'questiondown', 495 | 'exclamdown', 496 | 'parenleft', 497 | 'parenright', 498 | 'braceleft', 499 | 'braceright', 500 | 'bracketleft', 501 | 'bracketright', 502 | 'slash', 503 | 'backslash', 504 | 'underscore', 505 | 'hyphen', 506 | 'uni00AD', 507 | 'endash', 508 | 'emdash', 509 | 'brokenbar', 510 | 'bar', 511 | 'guillemotleft', 512 | 'guillemotright', 513 | 'guilsinglleft', 514 | 'guilsinglright', 515 | 'quotesinglbase', 516 | 'quotedblbase', 517 | 'quoteleft', 518 | 'quotedblleft', 519 | 'quoteright', 520 | 'quotedblright', 521 | 'quotesingle', 522 | 'quotedbl', 523 | 'bullet', 524 | 'ampersand', 525 | 'paragraph', 526 | 'dagger', 527 | 'daggerdbl', 528 | 'section', 529 | 'asterisk', 530 | 'trademark', 531 | 'registered', 532 | 'copyright', 533 | 'at', 534 | 'ordfeminine', 535 | 'ordmasculine', 536 | 537 | 'a.sup', 538 | 'b.sup', 539 | 'c.sup', 540 | 'd.sup', 541 | 'e.sup', 542 | 'f.sup', 543 | 'g.sup', 544 | 'h.sup', 545 | 'i.sup', 546 | 'j.sup', 547 | 'k.sup', 548 | 'l.sup', 549 | 'm.sup', 550 | 'n.sup', 551 | 'o.sup', 552 | 'p.sup', 553 | 'q.sup', 554 | 'r.sup', 555 | 's.sup', 556 | 't.sup', 557 | 'u.sup', 558 | 'v.sup', 559 | 'w.sup', 560 | 'x.sup', 561 | 'y.sup', 562 | 'z.sup', 563 | 564 | 'numbersign', 565 | 'Euro', 566 | 'dollar', 567 | 'yen', 568 | 'sterling', 569 | 'cent', 570 | 'florin', 571 | 'currency', 572 | 573 | 'zero', 574 | 'one', 575 | 'two', 576 | 'three', 577 | 'four', 578 | 'five', 579 | 'six', 580 | 'seven', 581 | 'eight', 582 | 'nine', 583 | 'zeroslash', 584 | 585 | 'numbersign.plf', 586 | 'Euro.plf', 587 | 'dollar.plf', 588 | 'yen.plf', 589 | 'sterling.plf', 590 | 'cent.plf', 591 | 'zero.plf', 592 | 'one.plf', 593 | 'two.plf', 594 | 'three.plf', 595 | 'four.plf', 596 | 'five.plf', 597 | 'six.plf', 598 | 'seven.plf', 599 | 'eight.plf', 600 | 'nine.plf', 601 | 'zeroslash.plf', 602 | 603 | 'numbersign.tlf', 604 | 'Euro.tlf', 605 | 'dollar.tlf', 606 | 'yen.tlf', 607 | 'sterling.tlf', 608 | 'cent.tlf', 609 | 'zero.tlf', 610 | 'one.tlf', 611 | 'two.tlf', 612 | 'three.tlf', 613 | 'four.tlf', 614 | 'five.tlf', 615 | 'six.tlf', 616 | 'seven.tlf', 617 | 'eight.tlf', 618 | 'nine.tlf', 619 | 'zeroslash.tlf', 620 | 621 | 'numbersign.tosf', 622 | 'Euro.tosf', 623 | 'dollar.tosf', 624 | 'yen.tosf', 625 | 'sterling.tosf', 626 | 'cent.tosf', 627 | 'zero.tosf', 628 | 'one.tosf', 629 | 'two.tosf', 630 | 'three.tosf', 631 | 'four.tosf', 632 | 'five.tosf', 633 | 'six.tosf', 634 | 'seven.tosf', 635 | 'eight.tosf', 636 | 'nine.tosf', 637 | 'zeroslash.tosf', 638 | 639 | 'numbersign.posf', 640 | 'Euro.posf', 641 | 'dollar.posf', 642 | 'yen.posf', 643 | 'sterling.posf', 644 | 'cent.posf', 645 | 'zero.posf', 646 | 'one.posf', 647 | 'two.posf', 648 | 'three.posf', 649 | 'four.posf', 650 | 'five.posf', 651 | 'six.posf', 652 | 'seven.posf', 653 | 'eight.posf', 654 | 'nine.posf', 655 | 'zeroslash.posf', 656 | 657 | 'numbersign.tscf', 658 | 'Euro.tscf', 659 | 'dollar.tscf', 660 | 'yen.tscf', 661 | 'sterling.tscf', 662 | 'cent.tscf', 663 | 'zero.tscf', 664 | 'one.tscf', 665 | 'two.tscf', 666 | 'three.tscf', 667 | 'four.tscf', 668 | 'five.tscf', 669 | 'six.tscf', 670 | 'seven.tscf', 671 | 'eight.tscf', 672 | 'nine.tscf', 673 | 'zeroslash.tscf', 674 | 675 | 'numbersign.pscf', 676 | 'Euro.pscf', 677 | 'dollar.pscf', 678 | 'yen.pscf', 679 | 'sterling.pscf', 680 | 'cent.pscf', 681 | 'zero.pscf', 682 | 'one.pscf', 683 | 'two.pscf', 684 | 'three.pscf', 685 | 'four.pscf', 686 | 'five.pscf', 687 | 'six.pscf', 688 | 'seven.pscf', 689 | 'eight.pscf', 690 | 'nine.pscf', 691 | 'zeroslash.pscf', 692 | 693 | 'percent.sc', 694 | 'perthousand.sc', 695 | 696 | 'degree', 697 | 'percent', 698 | 'perthousand', 699 | 700 | 'fraction', 701 | 'uni2215', 702 | 703 | 'zerosuperior', 704 | 'onesuperior', 705 | 'twosuperior', 706 | 'threesuperior', 707 | 'foursuperior', 708 | 'fivesuperior', 709 | 'sixsuperior', 710 | 'sevensuperior', 711 | 'eightsuperior', 712 | 'ninesuperior', 713 | 714 | 'onehalf', 715 | 'onequarter', 716 | 'threequarters', 717 | 'onethird', 718 | 'twothirds', 719 | 'oneeighth', 720 | 'threeeighths', 721 | 'fiveeighths', 722 | 'seveneighths', 723 | 'onefifth', 724 | 'twofifths', 725 | 'threefifths', 726 | 'fourfifths', 727 | 'onesixth', 728 | 'fivesixths', 729 | 'oneseventh', 730 | 'twosevenths', 731 | 'threesevenths', 732 | 'foursevenths', 733 | 'fivesevenths', 734 | 'sixsevenths', 735 | 'oneninth', 736 | 'twoninths', 737 | 'fourninths', 738 | 'fiveninths', 739 | 'sevenninths', 740 | 'eightninths', 741 | 742 | 'zeroinferior', 743 | 'oneinferior', 744 | 'twoinferior', 745 | 'threeinferior', 746 | 'fourinferior', 747 | 'fiveinferior', 748 | 'sixinferior', 749 | 'seveninferior', 750 | 'eightinferior', 751 | 'nineinferior', 752 | 753 | 'zero.numerator', 754 | 'one.numerator', 755 | 'two.numerator', 756 | 'three.numerator', 757 | 'four.numerator', 758 | 'five.numerator', 759 | 'six.numerator', 760 | 'seven.numerator', 761 | 'eight.numerator', 762 | 'nine.numerator', 763 | 764 | 'zero.denominator', 765 | 'one.denominator', 766 | 'two.denominator', 767 | 'three.denominator', 768 | 'four.denominator', 769 | 'five.denominator', 770 | 'six.denominator', 771 | 'seven.denominator', 772 | 'eight.denominator', 773 | 'nine.denominator', 774 | 775 | 'plus', 776 | 'minus', 777 | 'multiply', 778 | 'divide', 779 | 'equal', 780 | 'logicalnot', 781 | 'asciitilde', 782 | 'less', 783 | 'greater', 784 | 'plusminus', 785 | 'asciicircum', 786 | 'notequal', 787 | 'approxequal', 788 | 'lessequal', 789 | 'greaterequal', 790 | 'infinity', 791 | 'lozenge', 792 | 'radical', 793 | 'integral', 794 | 'partialdiff', 795 | 'product', 796 | 'pi', 797 | 'mu', 798 | 'summation', 799 | 'Omega', 800 | 'uni03A9', 801 | 'Delta', 802 | 'uni0394', 803 | 'uni2113', 804 | 'estimated', 805 | 'heart' 806 | ] 807 | 808 | 809 | encodingM = [ 810 | '.notdef', 811 | '.null', 812 | 'CR', 813 | 'space', 814 | 'uni00A0', 815 | 'A', 816 | 'B', 817 | 'C', 818 | 'D', 819 | 'E', 820 | 'F', 821 | 'G', 822 | 'H', 823 | 'I', 824 | 'J', 825 | 'K', 826 | 'L', 827 | 'M', 828 | 'N', 829 | 'O', 830 | 'P', 831 | 'Q', 832 | 'R', 833 | 'S', 834 | 'T', 835 | 'U', 836 | 'V', 837 | 'W', 838 | 'X', 839 | 'Y', 840 | 'Z', 841 | 'AE', 842 | 'OE', 843 | 'Lslash', 844 | 'Oslash', 845 | 'Eth', 846 | 'Thorn', 847 | 848 | 'a', 849 | 'b', 850 | 'c', 851 | 'd', 852 | 'e', 853 | 'f', 854 | 'g', 855 | 'h', 856 | 'i', 857 | 'j', 858 | 'k', 859 | 'l', 860 | 'm', 861 | 'n', 862 | 'o', 863 | 'p', 864 | 'q', 865 | 'r', 866 | 's', 867 | 't', 868 | 'u', 869 | 'v', 870 | 'w', 871 | 'x', 872 | 'y', 873 | 'z', 874 | 'ae', 875 | 'oe', 876 | 'lslash', 877 | 'oslash', 878 | 'eth', 879 | 'thorn', 880 | 'germandbls', 881 | 'dotlessi', 882 | 'dotlessj', 883 | 884 | 'fi', 885 | 'fl', 886 | 'f_f', 887 | 'f_f_i', 888 | 'f_f_l', 889 | 890 | 'Aacute', 891 | 'Acircumflex', 892 | 'Adieresis', 893 | 'Agrave', 894 | 'Aring', 895 | 'Atilde', 896 | 'Abreve', 897 | 'Amacron', 898 | 'Aogonek', 899 | 'Ccedilla', 900 | 'Cacute', 901 | 'Ccaron', 902 | 'Ccircumflex', 903 | 'Cdotaccent', 904 | 'Dcaron', 905 | 'Dcroat', 906 | 'Eacute', 907 | 'Ecircumflex', 908 | 'Edieresis', 909 | 'Egrave', 910 | 'Ebreve', 911 | 'Ecaron', 912 | 'Edotaccent', 913 | 'Emacron', 914 | 'Eogonek', 915 | 'Gbreve', 916 | 'Gcircumflex', 917 | 'Gcommaaccent', 918 | 'Gdotaccent', 919 | 'Hbar', 920 | 'Hcircumflex', 921 | 'Iacute', 922 | 'Icircumflex', 923 | 'Idieresis', 924 | 'Igrave', 925 | 'Ibreve', 926 | 'Idotaccent', 927 | 'Imacron', 928 | 'Iogonek', 929 | 'Itilde', 930 | 'Jcircumflex', 931 | 'IJ', 932 | 'Kcommaaccent', 933 | 'Lacute', 934 | 'Lcaron', 935 | 'Lcommaaccent', 936 | 'Ldot', 937 | 'Ntilde', 938 | 'Nacute', 939 | 'Ncaron', 940 | 'Ncommaaccent', 941 | 'Oacute', 942 | 'Ocircumflex', 943 | 'Odieresis', 944 | 'Ograve', 945 | 'Otilde', 946 | 'Obreve', 947 | 'Ohungarumlaut', 948 | 'Omacron', 949 | 'Racute', 950 | 'Rcaron', 951 | 'Rcommaaccent', 952 | 'Scaron', 953 | 'Sacute', 954 | 'Scedilla', 955 | 'Scircumflex', 956 | 'uni0218', 957 | 'Tbar', 958 | 'Tcaron', 959 | 'uni0162', 960 | 'uni021A', 961 | 'Uacute', 962 | 'Ucircumflex', 963 | 'Udieresis', 964 | 'Ugrave', 965 | 'Ubreve', 966 | 'Uhungarumlaut', 967 | 'Umacron', 968 | 'Uogonek', 969 | 'Uring', 970 | 'Utilde', 971 | 'Wacute', 972 | 'Wcircumflex', 973 | 'Wdieresis', 974 | 'Wgrave', 975 | 'Yacute', 976 | 'Ydieresis', 977 | 'Ycircumflex', 978 | 'Ygrave', 979 | 'Zcaron', 980 | 'Zacute', 981 | 'Zdotaccent', 982 | 983 | 'aacute', 984 | 'acircumflex', 985 | 'adieresis', 986 | 'agrave', 987 | 'aring', 988 | 'atilde', 989 | 'abreve', 990 | 'amacron', 991 | 'aogonek', 992 | 'ccedilla', 993 | 'cacute', 994 | 'ccaron', 995 | 'ccircumflex', 996 | 'cdotaccent', 997 | 'dcaron', 998 | 'dcroat', 999 | 'eacute', 1000 | 'ecircumflex', 1001 | 'edieresis', 1002 | 'egrave', 1003 | 'ebreve', 1004 | 'ecaron', 1005 | 'edotaccent', 1006 | 'emacron', 1007 | 'eogonek', 1008 | 'gbreve', 1009 | 'gcircumflex', 1010 | 'gcommaaccent', 1011 | 'gdotaccent', 1012 | 'hbar', 1013 | 'hcircumflex', 1014 | 'iacute', 1015 | 'icircumflex', 1016 | 'idieresis', 1017 | 'igrave', 1018 | 'ibreve', 1019 | 'i.dot', 1020 | 'imacron', 1021 | 'iogonek', 1022 | 'itilde', 1023 | 'jcircumflex', 1024 | 'ij', 1025 | 'kcommaaccent', 1026 | 'lacute', 1027 | 'lcaron', 1028 | 'lcommaaccent', 1029 | 'ldot', 1030 | 'ntilde', 1031 | 'nacute', 1032 | 'ncaron', 1033 | 'ncommaaccent', 1034 | 'oacute', 1035 | 'ocircumflex', 1036 | 'odieresis', 1037 | 'ograve', 1038 | 'otilde', 1039 | 'obreve', 1040 | 'ohungarumlaut', 1041 | 'omacron', 1042 | 'racute', 1043 | 'rcaron', 1044 | 'rcommaaccent', 1045 | 'scaron', 1046 | 'sacute', 1047 | 'scedilla', 1048 | 'scircumflex', 1049 | 'uni0219', 1050 | 'tbar', 1051 | 'tcaron', 1052 | 'uni0163', 1053 | 'uni021B', 1054 | 'uacute', 1055 | 'ucircumflex', 1056 | 'udieresis', 1057 | 'ugrave', 1058 | 'ubreve', 1059 | 'uhungarumlaut', 1060 | 'umacron', 1061 | 'uogonek', 1062 | 'uring', 1063 | 'utilde', 1064 | 'wacute', 1065 | 'wcircumflex', 1066 | 'wdieresis', 1067 | 'wgrave', 1068 | 'yacute', 1069 | 'ydieresis', 1070 | 'ycircumflex', 1071 | 'ygrave', 1072 | 'zcaron', 1073 | 'zacute', 1074 | 'zdotaccent', 1075 | 1076 | 'acute', 1077 | 'grave', 1078 | 'circumflex', 1079 | 'caron', 1080 | 'tilde', 1081 | 'dieresis', 1082 | 'ring', 1083 | 'cedilla', 1084 | 1085 | 'hungarumlaut', 1086 | 'breve', 1087 | 'macron', 1088 | 'dotaccent', 1089 | 'periodcentered', 1090 | 'ogonek', 1091 | 'commaaccent', 1092 | 1093 | 'caron.alt', 1094 | 'revcommaaccent', 1095 | 1096 | 'acute.cap', 1097 | 'grave.cap', 1098 | 'circumflex.cap', 1099 | 'caron.cap', 1100 | 'tilde.cap', 1101 | 'dieresis.cap', 1102 | 'ring.cap', 1103 | 'cedilla.cap', 1104 | 1105 | 'hungarumlaut.cap', 1106 | 'breve.cap', 1107 | 'macron.cap', 1108 | 'dotaccent.cap', 1109 | 'ogonek.cap', 1110 | 'commaaccent.cap', 1111 | 'caron.alt.cap', 1112 | 1113 | 'period', 1114 | 'comma', 1115 | 'colon', 1116 | 'semicolon', 1117 | 'ellipsis', 1118 | 'question', 1119 | 'exclam', 1120 | 'questiondown', 1121 | 'exclamdown', 1122 | 'parenleft', 1123 | 'parenright', 1124 | 'braceleft', 1125 | 'braceright', 1126 | 'bracketleft', 1127 | 'bracketright', 1128 | 'slash', 1129 | 'backslash', 1130 | 'underscore', 1131 | 'hyphen', 1132 | 'uni00AD', 1133 | 'endash', 1134 | 'emdash', 1135 | 'brokenbar', 1136 | 'bar', 1137 | 'guillemotleft', 1138 | 'guillemotright', 1139 | 'guilsinglleft', 1140 | 'guilsinglright', 1141 | 'quotesinglbase', 1142 | 'quotedblbase', 1143 | 'quoteleft', 1144 | 'quotedblleft', 1145 | 'quoteright', 1146 | 'quotedblright', 1147 | 'quotesingle', 1148 | 'quotedbl', 1149 | 'bullet', 1150 | 'ampersand', 1151 | 'paragraph', 1152 | 'dagger', 1153 | 'daggerdbl', 1154 | 'section', 1155 | 'asterisk', 1156 | 'trademark', 1157 | 'registered', 1158 | 'copyright', 1159 | 'at', 1160 | 'ordfeminine', 1161 | 'ordmasculine', 1162 | 1163 | 'numbersign', 1164 | 'Euro', 1165 | 'dollar', 1166 | 'yen', 1167 | 'sterling', 1168 | 'cent', 1169 | 'florin', 1170 | 'currency', 1171 | 1172 | 'zero', 1173 | 'one', 1174 | 'two', 1175 | 'three', 1176 | 'four', 1177 | 'five', 1178 | 'six', 1179 | 'seven', 1180 | 'eight', 1181 | 'nine', 1182 | 'zeroslash', 1183 | 1184 | 'numbersign.plf', 1185 | 'Euro.plf', 1186 | 'dollar.plf', 1187 | 'yen.plf', 1188 | 'sterling.plf', 1189 | 'cent.plf', 1190 | 'zero.plf', 1191 | 'one.plf', 1192 | 'two.plf', 1193 | 'three.plf', 1194 | 'four.plf', 1195 | 'five.plf', 1196 | 'six.plf', 1197 | 'seven.plf', 1198 | 'eight.plf', 1199 | 'nine.plf', 1200 | 'zeroslash.plf', 1201 | 1202 | 'numbersign.tlf', 1203 | 'Euro.tlf', 1204 | 'dollar.tlf', 1205 | 'yen.tlf', 1206 | 'sterling.tlf', 1207 | 'cent.tlf', 1208 | 'zero.tlf', 1209 | 'one.tlf', 1210 | 'two.tlf', 1211 | 'three.tlf', 1212 | 'four.tlf', 1213 | 'five.tlf', 1214 | 'six.tlf', 1215 | 'seven.tlf', 1216 | 'eight.tlf', 1217 | 'nine.tlf', 1218 | 'zeroslash.tlf', 1219 | 1220 | 'numbersign.tosf', 1221 | 'Euro.tosf', 1222 | 'dollar.tosf', 1223 | 'yen.tosf', 1224 | 'sterling.tosf', 1225 | 'cent.tosf', 1226 | 'zero.tosf', 1227 | 'one.tosf', 1228 | 'two.tosf', 1229 | 'three.tosf', 1230 | 'four.tosf', 1231 | 'five.tosf', 1232 | 'six.tosf', 1233 | 'seven.tosf', 1234 | 'eight.tosf', 1235 | 'nine.tosf', 1236 | 'zeroslash.tosf', 1237 | 1238 | 'numbersign.posf', 1239 | 'Euro.posf', 1240 | 'dollar.posf', 1241 | 'yen.posf', 1242 | 'sterling.posf', 1243 | 'cent.posf', 1244 | 'zero.posf', 1245 | 'one.posf', 1246 | 'two.posf', 1247 | 'three.posf', 1248 | 'four.posf', 1249 | 'five.posf', 1250 | 'six.posf', 1251 | 'seven.posf', 1252 | 'eight.posf', 1253 | 'nine.posf', 1254 | 'zeroslash.posf', 1255 | 1256 | 'degree', 1257 | 'percent', 1258 | 'perthousand', 1259 | 1260 | 'fraction', 1261 | 'uni2215', 1262 | 1263 | 'zerosuperior', 1264 | 'onesuperior', 1265 | 'twosuperior', 1266 | 'threesuperior', 1267 | 'foursuperior', 1268 | 'fivesuperior', 1269 | 'sixsuperior', 1270 | 'sevensuperior', 1271 | 'eightsuperior', 1272 | 'ninesuperior', 1273 | 1274 | 'onehalf', 1275 | 'onequarter', 1276 | 'threequarters', 1277 | 'onethird', 1278 | 'twothirds', 1279 | 'oneeighth', 1280 | 'threeeighths', 1281 | 'fiveeighths', 1282 | 'seveneighths', 1283 | 'onefifth', 1284 | 'twofifths', 1285 | 'threefifths', 1286 | 'fourfifths', 1287 | 'onesixth', 1288 | 'fivesixths', 1289 | 'oneseventh', 1290 | 'twosevenths', 1291 | 'threesevenths', 1292 | 'foursevenths', 1293 | 'fivesevenths', 1294 | 'sixsevenths', 1295 | 'oneninth', 1296 | 'twoninths', 1297 | 'fourninths', 1298 | 'fiveninths', 1299 | 'sevenninths', 1300 | 'eightninths', 1301 | 1302 | 'zeroinferior', 1303 | 'oneinferior', 1304 | 'twoinferior', 1305 | 'threeinferior', 1306 | 'fourinferior', 1307 | 'fiveinferior', 1308 | 'sixinferior', 1309 | 'seveninferior', 1310 | 'eightinferior', 1311 | 'nineinferior', 1312 | 1313 | 'zero.numerator', 1314 | 'one.numerator', 1315 | 'two.numerator', 1316 | 'three.numerator', 1317 | 'four.numerator', 1318 | 'five.numerator', 1319 | 'six.numerator', 1320 | 'seven.numerator', 1321 | 'eight.numerator', 1322 | 'nine.numerator', 1323 | 1324 | 'zero.denominator', 1325 | 'one.denominator', 1326 | 'two.denominator', 1327 | 'three.denominator', 1328 | 'four.denominator', 1329 | 'five.denominator', 1330 | 'six.denominator', 1331 | 'seven.denominator', 1332 | 'eight.denominator', 1333 | 'nine.denominator', 1334 | 1335 | 'plus', 1336 | 'minus', 1337 | 'multiply', 1338 | 'divide', 1339 | 'equal', 1340 | 'logicalnot', 1341 | 'asciitilde', 1342 | 'less', 1343 | 'greater', 1344 | 'plusminus', 1345 | 'asciicircum', 1346 | 'notequal', 1347 | 'approxequal', 1348 | 'lessequal', 1349 | 'greaterequal', 1350 | 'infinity', 1351 | 'lozenge', 1352 | 'radical', 1353 | 'integral', 1354 | 'partialdiff', 1355 | 'product', 1356 | 'pi', 1357 | 'mu', 1358 | 'summation', 1359 | 'Omega', 1360 | 'uni03A9', 1361 | 'Delta', 1362 | 'uni0394', 1363 | 'uni2113', 1364 | 'estimated', 1365 | 'heart' 1366 | ] 1367 | 1368 | encodingS = [ 1369 | '.notdef', 1370 | '.null', 1371 | 'CR', 1372 | 'space', 1373 | 'uni00A0', 1374 | 'A', 1375 | 'B', 1376 | 'C', 1377 | 'D', 1378 | 'E', 1379 | 'F', 1380 | 'G', 1381 | 'H', 1382 | 'I', 1383 | 'J', 1384 | 'K', 1385 | 'L', 1386 | 'M', 1387 | 'N', 1388 | 'O', 1389 | 'P', 1390 | 'Q', 1391 | 'R', 1392 | 'S', 1393 | 'T', 1394 | 'U', 1395 | 'V', 1396 | 'W', 1397 | 'X', 1398 | 'Y', 1399 | 'Z', 1400 | 'AE', 1401 | 'OE', 1402 | 'Lslash', 1403 | 'Oslash', 1404 | 'Eth', 1405 | 'Thorn', 1406 | 'a', 1407 | 'b', 1408 | 'c', 1409 | 'd', 1410 | 'e', 1411 | 'f', 1412 | 'g', 1413 | 'h', 1414 | 'i', 1415 | 'j', 1416 | 'k', 1417 | 'l', 1418 | 'm', 1419 | 'n', 1420 | 'o', 1421 | 'p', 1422 | 'q', 1423 | 'r', 1424 | 's', 1425 | 't', 1426 | 'u', 1427 | 'v', 1428 | 'w', 1429 | 'x', 1430 | 'y', 1431 | 'z', 1432 | 'ae', 1433 | 'oe', 1434 | 'lslash', 1435 | 'oslash', 1436 | 'eth', 1437 | 'thorn', 1438 | 'germandbls', 1439 | 'dotlessi', 1440 | 'dotlessj', 1441 | 'fi', 1442 | 'fl', 1443 | 'Aacute', 1444 | 'Acircumflex', 1445 | 'Adieresis', 1446 | 'Agrave', 1447 | 'Aring', 1448 | 'Atilde', 1449 | 'Abreve', 1450 | 'Amacron', 1451 | 'Aogonek', 1452 | 'Ccedilla', 1453 | 'Cacute', 1454 | 'Ccaron', 1455 | 'Ccircumflex', 1456 | 'Cdotaccent', 1457 | 'Dcaron', 1458 | 'Dcroat', 1459 | 'Eacute', 1460 | 'Ecircumflex', 1461 | 'Edieresis', 1462 | 'Egrave', 1463 | 'Ebreve', 1464 | 'Ecaron', 1465 | 'Edotaccent', 1466 | 'Emacron', 1467 | 'Eogonek', 1468 | 'Gbreve', 1469 | 'Gcircumflex', 1470 | 'Gcommaaccent', 1471 | 'Gdotaccent', 1472 | 'Hbar', 1473 | 'Hcircumflex', 1474 | 'Iacute', 1475 | 'Icircumflex', 1476 | 'Idieresis', 1477 | 'Igrave', 1478 | 'Ibreve', 1479 | 'Idotaccent', 1480 | 'Imacron', 1481 | 'Iogonek', 1482 | 'Itilde', 1483 | 'Jcircumflex', 1484 | 'IJ', 1485 | 'Kcommaaccent', 1486 | 'Lacute', 1487 | 'Lcaron', 1488 | 'Lcommaaccent', 1489 | 'Ldot', 1490 | 'Ntilde', 1491 | 'Nacute', 1492 | 'Ncaron', 1493 | 'Ncommaaccent', 1494 | 'Oacute', 1495 | 'Ocircumflex', 1496 | 'Odieresis', 1497 | 'Ograve', 1498 | 'Otilde', 1499 | 'Obreve', 1500 | 'Ohungarumlaut', 1501 | 'Omacron', 1502 | 'Racute', 1503 | 'Rcaron', 1504 | 'Rcommaaccent', 1505 | 'Scaron', 1506 | 'Sacute', 1507 | 'Scedilla', 1508 | 'Scircumflex', 1509 | 'uni0218', 1510 | 'Tbar', 1511 | 'Tcaron', 1512 | 'uni0162', 1513 | 'uni021A', 1514 | 'Uacute', 1515 | 'Ucircumflex', 1516 | 'Udieresis', 1517 | 'Ugrave', 1518 | 'Ubreve', 1519 | 'Uhungarumlaut', 1520 | 'Umacron', 1521 | 'Uogonek', 1522 | 'Uring', 1523 | 'Utilde', 1524 | 'Wacute', 1525 | 'Wcircumflex', 1526 | 'Wdieresis', 1527 | 'Wgrave', 1528 | 'Yacute', 1529 | 'Ydieresis', 1530 | 'Ycircumflex', 1531 | 'Ygrave', 1532 | 'Zcaron', 1533 | 'Zacute', 1534 | 'Zdotaccent', 1535 | 'aacute', 1536 | 'acircumflex', 1537 | 'adieresis', 1538 | 'agrave', 1539 | 'aring', 1540 | 'atilde', 1541 | 'abreve', 1542 | 'amacron', 1543 | 'aogonek', 1544 | 'ccedilla', 1545 | 'cacute', 1546 | 'ccaron', 1547 | 'ccircumflex', 1548 | 'cdotaccent', 1549 | 'dcaron', 1550 | 'dcroat', 1551 | 'eacute', 1552 | 'ecircumflex', 1553 | 'edieresis', 1554 | 'egrave', 1555 | 'ebreve', 1556 | 'ecaron', 1557 | 'edotaccent', 1558 | 'emacron', 1559 | 'eogonek', 1560 | 'gbreve', 1561 | 'gcircumflex', 1562 | 'gcommaaccent', 1563 | 'gdotaccent', 1564 | 'hbar', 1565 | 'hcircumflex', 1566 | 'iacute', 1567 | 'icircumflex', 1568 | 'idieresis', 1569 | 'igrave', 1570 | 'ibreve', 1571 | 'i.dot', 1572 | 'imacron', 1573 | 'iogonek', 1574 | 'itilde', 1575 | 'jcircumflex', 1576 | 'ij', 1577 | 'kcommaaccent', 1578 | 'lacute', 1579 | 'lcaron', 1580 | 'lcommaaccent', 1581 | 'ldot', 1582 | 'ntilde', 1583 | 'nacute', 1584 | 'ncaron', 1585 | 'ncommaaccent', 1586 | 'oacute', 1587 | 'ocircumflex', 1588 | 'odieresis', 1589 | 'ograve', 1590 | 'otilde', 1591 | 'obreve', 1592 | 'ohungarumlaut', 1593 | 'omacron', 1594 | 'racute', 1595 | 'rcaron', 1596 | 'rcommaaccent', 1597 | 'scaron', 1598 | 'sacute', 1599 | 'scedilla', 1600 | 'scircumflex', 1601 | 'uni0219', 1602 | 'tbar', 1603 | 'tcaron', 1604 | 'uni0163', 1605 | 'uni021B', 1606 | 'uacute', 1607 | 'ucircumflex', 1608 | 'udieresis', 1609 | 'ugrave', 1610 | 'ubreve', 1611 | 'uhungarumlaut', 1612 | 'umacron', 1613 | 'uogonek', 1614 | 'uring', 1615 | 'utilde', 1616 | 'wacute', 1617 | 'wcircumflex', 1618 | 'wdieresis', 1619 | 'wgrave', 1620 | 'yacute', 1621 | 'ydieresis', 1622 | 'ycircumflex', 1623 | 'ygrave', 1624 | 'zcaron', 1625 | 'zacute', 1626 | 'zdotaccent', 1627 | 'acute', 1628 | 'grave', 1629 | 'circumflex', 1630 | 'caron', 1631 | 'tilde', 1632 | 'dieresis', 1633 | 'ring', 1634 | 'cedilla', 1635 | 'hungarumlaut', 1636 | 'breve', 1637 | 'macron', 1638 | 'dotaccent', 1639 | 'periodcentered', 1640 | 'ogonek', 1641 | 'commaaccent', 1642 | 'caron.alt', 1643 | 'revcommaaccent', 1644 | 'acute.cap', 1645 | 'grave.cap', 1646 | 'circumflex.cap', 1647 | 'caron.cap', 1648 | 'tilde.cap', 1649 | 'dieresis.cap', 1650 | 'ring.cap', 1651 | 'cedilla.cap', 1652 | 'hungarumlaut.cap', 1653 | 'breve.cap', 1654 | 'macron.cap', 1655 | 'dotaccent.cap', 1656 | 'ogonek.cap', 1657 | 'commaaccent.cap', 1658 | 'caron.alt.cap', 1659 | 'period', 1660 | 'comma', 1661 | 'colon', 1662 | 'semicolon', 1663 | 'ellipsis', 1664 | 'question', 1665 | 'exclam', 1666 | 'questiondown', 1667 | 'exclamdown', 1668 | 'parenleft', 1669 | 'parenright', 1670 | 'braceleft', 1671 | 'braceright', 1672 | 'bracketleft', 1673 | 'bracketright', 1674 | 'slash', 1675 | 'backslash', 1676 | 'underscore', 1677 | 'hyphen', 1678 | 'uni00AD', 1679 | 'endash', 1680 | 'emdash', 1681 | 'brokenbar', 1682 | 'bar', 1683 | 'guillemotleft', 1684 | 'guillemotright', 1685 | 'guilsinglleft', 1686 | 'guilsinglright', 1687 | 'quotesinglbase', 1688 | 'quotedblbase', 1689 | 'quoteleft', 1690 | 'quotedblleft', 1691 | 'quoteright', 1692 | 'quotedblright', 1693 | 'quotesingle', 1694 | 'quotedbl', 1695 | 'bullet', 1696 | 'ampersand', 1697 | 'paragraph', 1698 | 'dagger', 1699 | 'daggerdbl', 1700 | 'section', 1701 | 'asterisk', 1702 | 'trademark', 1703 | 'registered', 1704 | 'copyright', 1705 | 'at', 1706 | 'ordfeminine', 1707 | 'ordmasculine', 1708 | 'numbersign', 1709 | 'Euro', 1710 | 'dollar', 1711 | 'yen', 1712 | 'sterling', 1713 | 'cent', 1714 | 'florin', 1715 | 'currency', 1716 | 'zero', 1717 | 'one', 1718 | 'two', 1719 | 'three', 1720 | 'four', 1721 | 'five', 1722 | 'six', 1723 | 'seven', 1724 | 'eight', 1725 | 'nine', 1726 | 'degree', 1727 | 'percent', 1728 | 'perthousand', 1729 | 'fraction', 1730 | 'uni2215', 1731 | 'onesuperior', 1732 | 'twosuperior', 1733 | 'threesuperior', 1734 | 'foursuperior', 1735 | 'onehalf', 1736 | 'onequarter', 1737 | 'threequarters', 1738 | 'plus', 1739 | 'minus', 1740 | 'multiply', 1741 | 'divide', 1742 | 'equal', 1743 | 'logicalnot', 1744 | 'asciitilde', 1745 | 'less', 1746 | 'greater', 1747 | 'plusminus', 1748 | 'asciicircum', 1749 | 'notequal', 1750 | 'approxequal', 1751 | 'lessequal', 1752 | 'greaterequal', 1753 | 'infinity', 1754 | 'lozenge', 1755 | 'radical', 1756 | 'integral', 1757 | 'partialdiff', 1758 | 'product', 1759 | 'pi', 1760 | 'mu', 1761 | 'summation', 1762 | 'Omega', 1763 | 'uni03A9', 1764 | 'Delta', 1765 | 'uni0394', 1766 | 'uni2113', 1767 | 'estimated', 1768 | 'heart' 1769 | 1770 | ] 1771 | 1772 | class Process(BaseWindowController): 1773 | 1774 | def __init__(self): 1775 | self.w = FloatingWindow((310, 200)) 1776 | self.w.textBox = TextBox((10, 10, -10, 16), "GlyphSet", sizeStyle = "regular", alignment = "center") 1777 | self.w.textBoxEncodingS = CheckBox((10, 40, -10, 20), "Encoding S", sizeStyle = "small", 1778 | callback=self.textBoxEncodingSCallback, value = False) 1779 | self.w.textBoxEncodingM = CheckBox((10, 70, -10, 20), "Encoding M", sizeStyle = "small", 1780 | callback=self.textBoxEncodingMCallback, value = False) 1781 | self.w.textBoxEncodingL = CheckBox((10, 100, -10, 20), "Encoding L", sizeStyle = "small", 1782 | callback=self.textBoxEncodingLCallback, value = False) 1783 | self.w.textBoxEncodingNone = CheckBox((10, 130, -10, 20), "None", sizeStyle = "small", 1784 | callback=self.textBoxEncodingNoneCallback, value = False) 1785 | self.w.buttonApply = Button((10, -20, 90, 15), "Apply", sizeStyle = "small", callback=self.showProgress) 1786 | self.w.buttonClose = Button((210, -20, 90, 15), "Close", sizeStyle = "small", callback=self.closeWindow) 1787 | self.w.center() 1788 | self.w.open() 1789 | 1790 | def closeWindow(self, sender): 1791 | self.w.close() 1792 | 1793 | def textBoxEncodingSCallback(self, sender): 1794 | if sender.get(): 1795 | self.w.textBoxEncodingM.set(False) 1796 | self.w.textBoxEncodingL.set(False) 1797 | self.w.textBoxEncodingNone.set(False) 1798 | 1799 | def textBoxEncodingMCallback(self, sender): 1800 | if sender.get(): 1801 | self.w.textBoxEncodingS.set(False) 1802 | self.w.textBoxEncodingL.set(False) 1803 | self.w.textBoxEncodingNone.set(False) 1804 | 1805 | def textBoxEncodingLCallback(self, sender): 1806 | if sender.get(): 1807 | self.w.textBoxEncodingS.set(False) 1808 | self.w.textBoxEncodingM.set(False) 1809 | self.w.textBoxEncodingNone.set(False) 1810 | 1811 | def textBoxEncodingNoneCallback(self, sender): 1812 | if sender.get(): 1813 | self.w.textBoxEncodingS.set(False) 1814 | self.w.textBoxEncodingM.set(False) 1815 | self.w.textBoxEncodingL.set(False) 1816 | 1817 | def showProgress(self, sender): 1818 | self.progress = self.startProgress("Updating Encoding...") 1819 | if self.w.textBoxEncodingL.get(): 1820 | f.glyphOrder = encodingL 1821 | self.progress.close() 1822 | elif self.w.textBoxEncodingM.get(): 1823 | f.glyphOrder = encodingM 1824 | self.progress.close() 1825 | elif self.w.textBoxEncodingS.get(): 1826 | f.glyphOrder = encodingS 1827 | self.progress.close() 1828 | elif self.w.textBoxEncodingNone.get(): 1829 | f.glyphOrder = [] 1830 | self.progress.close() 1831 | self.w.close() 1832 | 1833 | 1834 | f = CurrentFont() 1835 | Process() -------------------------------------------------------------------------------- /ExpandKerning/ExpandKerning.py: -------------------------------------------------------------------------------- 1 | f = CurrentFont() 2 | cachedKerning = f.kerning 3 | 4 | #print pair, value 5 | def expandKerning(kerningItems): 6 | expandedKerning = {} 7 | for (pair, value) in kerningItems: 8 | if pair[0][:4] == '@MMK' and pair[1][:4] == '@MMK': 9 | #print 'Left and Right are groups' 10 | for c_keyLeft in f.groups.keys(): 11 | if c_keyLeft == pair[0]: 12 | #print f.groups[c_keyLeft] 13 | for gLeftname in f.groups[c_keyLeft]: 14 | for c_keyRight in f.groups.keys(): 15 | if c_keyRight == pair[1]: 16 | #print f.groups[c_keyRight] 17 | for gRightname in f.groups[c_keyRight]: 18 | processedpair = (gLeftname, gRightname) 19 | expandedKerning[processedpair] = value 20 | 21 | elif pair[1][:4] == '@MMK': 22 | #print 'Right only is group' 23 | for c_keyRight in f.groups.keys(): 24 | if c_keyRight == pair[1]: 25 | #print f.groups[c_keyRight] 26 | for gname in f.groups[c_keyRight]: 27 | processedpair = (pair[0], gname) 28 | expandedKerning[processedpair] = value 29 | 30 | elif pair[0][:4] == '@MMK': 31 | #print 'Left only is group' 32 | for c_keyLeft in f.groups.keys(): 33 | if c_keyLeft == pair[0]: 34 | #print f.groups[c_keyLeft] 35 | for gname in f.groups[c_keyLeft]: 36 | processedpair = (gname, pair[1]) 37 | expandedKerning[processedpair] = value 38 | 39 | else: 40 | #print 'none is group' 41 | expandedKerning[pair] = value 42 | 43 | return expandedKerning 44 | 45 | print 'expanding kerning...' 46 | myexpandedKerning = expandKerning(cachedKerning.items()) 47 | print 'clearing kerning...' 48 | f.kerning.clear() 49 | print 'import new flat kerning...' 50 | for pair, value in myexpandedKerning.iteritems(): 51 | f.kerning[pair] = value 52 | #print pair, value 53 | print 'clearing groups...' 54 | f.groups.clear() 55 | print 'DONE' 56 | -------------------------------------------------------------------------------- /GenerateFont/GenerateFont.py: -------------------------------------------------------------------------------- 1 | from vanilla import * 2 | from fontTools import * 3 | from mojo.events import * 4 | from defconAppKit.windows.baseWindow import BaseWindowController 5 | from os import * 6 | import math 7 | 8 | 9 | class GenerateWindow(BaseWindowController): 10 | 11 | def __init__(self): 12 | 13 | addObserver(self, "fontGenerated", "fontDidGenerate") 14 | 15 | self.decompose = False 16 | self.checkOutlines = False 17 | self.autohint = False 18 | self.releaseMode = False 19 | self.writeKern = False 20 | self.expandKern = False 21 | self.formatList = ["otf", "ttf"] 22 | self.formatIndex = 0 23 | self.formatName = "otf" 24 | 25 | self.w = FloatingWindow((310, 200), "Generate Font") 26 | 27 | self.w.formatTextBox = TextBox((10, 10, 100, 20), "Format") 28 | self.w.popUpButtonFormat = PopUpButton((10, 30, 100, 20), 29 | self.formatList, sizeStyle = "small", callback=self.popUpButtonFormatCallback) 30 | 31 | self.w.checkBoxDecompose = CheckBox((10, 60, 150, 20), "Decompose", sizeStyle = "small", 32 | callback=self.checkBoxDecomposeCallback, value = False) 33 | self.w.checkBoxRemoveOverlap = CheckBox((10, 80, 150, 20), "Remove Overlap", sizeStyle = "small", 34 | callback=self.checkBoxRemoveOverlapCallback, value = False) 35 | self.w.checkBoxAutoHint = CheckBox((10, 100, 150, 20), "AutoHint", sizeStyle = "small", 36 | callback=self.checkBoxAutoHintCallback, value = False) 37 | self.w.checkBoxReleaseMode = CheckBox((10, 120, 150, 20), "Release Mode", sizeStyle = "small", 38 | callback=self.checkBoxReleaseModeCallback, value = False) 39 | 40 | self.w.checkBoxWriteKern = CheckBox((160, 60, -10, 20), "Write Kern Table", sizeStyle = "small", 41 | callback=self.checkBoxWriteKernCallback, value = False) 42 | self.w.checkBoxExpandKerning = CheckBox((160, 80, -10, 20), "Expand Class Kerning", sizeStyle = "mini", 43 | callback=self.checkBoxExpandKerningCallback, value = False) 44 | self.w.checkBoxExpandKerning.show(0) 45 | 46 | 47 | self.w.buttonGenerate = Button((10, -25, 90, 15), "Generate", sizeStyle = "small", callback=self.generateFont) 48 | self.w.buttonGenerateAll = Button((110, -25, 90, 15), "Generate All", sizeStyle = "small", callback=self.generateAllFonts) 49 | self.w.buttonClose = Button((210, -25, 90, 15), "Close", sizeStyle = "small", callback=self.closeWindow) 50 | 51 | 52 | self.w.center() 53 | self.showGetFolder(callback=self.openFolderCallBack) 54 | 55 | self.w.open() 56 | 57 | 58 | def closeWindow(self, sender): 59 | removeObserver(self, "fontgenerated") 60 | self.w.close() 61 | 62 | 63 | def popUpButtonFormatCallback(self, sender): 64 | self.formatIndex == sender.get() 65 | self.formatName = self.formatList[sender.get()] 66 | 67 | def checkBoxDecomposeCallback(self, sender): 68 | if sender.get() == 0: 69 | self.decompose = False 70 | else: 71 | self.decompose = True 72 | 73 | def checkBoxRemoveOverlapCallback(self, sender): 74 | if sender.get() == 0: 75 | self.checkOutlines = False 76 | else: 77 | self.checkOutlines = True 78 | 79 | def checkBoxAutoHintCallback(self, sender): 80 | if sender.get() == 0: 81 | self.autohint = False 82 | else: 83 | self.autohint = True 84 | 85 | def checkBoxReleaseModeCallback(self, sender): 86 | if sender.get() == 0: 87 | self.releaseMode = False 88 | else: 89 | self.releaseMode = True 90 | 91 | def checkBoxWriteKernCallback(self, sender): 92 | if sender.get() == 0: 93 | self.writeKern = False 94 | else: 95 | self.writeKern = True 96 | self.w.checkBoxExpandKerning.show(sender.get()) 97 | 98 | def checkBoxExpandKerningCallback(self, sender): 99 | if sender.get() == 0: 100 | self.expandKern = False 101 | else: 102 | self.expandKern = True 103 | 104 | def generateFont(self, sender): 105 | self.fontName = '' 106 | familyNameList = f.info.openTypeNamePreferredFamilyName.split(' ') 107 | for i in familyNameList: 108 | self.fontName += i 109 | self.fontName += '-' + f.info.openTypeNamePreferredSubfamilyName + '.' + self.formatName 110 | 111 | self.fontpath = path.join(self.savingfolderpath, self.fontName) 112 | print self.fontpath 113 | 114 | self.progress = self.startProgress() 115 | 116 | f.generate(self.fontpath, self.formatName, self.decompose, self.checkOutlines, self.autohint, self.releaseMode, glyphOrder=None, progressBar = self.progress) 117 | self.progress.close() 118 | if self.writeKern == True: 119 | self.addKerntable(f) 120 | 121 | 122 | def generateAllFonts(self, sender): 123 | for f in af: 124 | self.fontName = '' 125 | familyNameList = f.info.openTypeNamePreferredFamilyName.split(' ') 126 | for i in familyNameList: 127 | self.fontName += i 128 | self.fontName += '-' + f.info.openTypeNamePreferredSubfamilyName + '.' + self.formatName 129 | 130 | self.fontpath = path.join(self.savingfolderpath, self.fontName) 131 | print self.fontpath 132 | 133 | self.progress = self.startProgress() 134 | 135 | f.generate(self.fontpath, self.formatName, self.decompose, self.checkOutlines, self.autohint, self.releaseMode, glyphOrder=None, progressBar = self.progress) 136 | self.progress.close() 137 | if self.writeKern == True: 138 | self.addKerntable(f) 139 | 140 | 141 | def openFolderCallBack(self, sender): 142 | self.savingfolderpath = sender[0] 143 | 144 | def addKerntable(self, f): 145 | 146 | (head, tail) = path.split(self.fontpath) 147 | tail = tail[:-4] 148 | tail += '_kern.' + self.formatName 149 | fontpath_kern = path.join(head, tail) 150 | 151 | tt = ttLib.TTFont(self.fontpath) 152 | myKernTable = ttLib.newTable('kern') 153 | myKernTable.version = 0 154 | # myKernSubTable = ttLib.tables._k_e_r_n.KernTable_format_0() 155 | # myKernSubTable.kernTable = {} 156 | 157 | cachedKerning = f.kerning 158 | allKerning = self.parseKerning(f, cachedKerning.items()) 159 | print len(allKerning) 160 | listOfSubTables = [] 161 | for i in range(int(math.ceil(len(allKerning)/10920))): 162 | listOfSubTables.append(allKerning[i*10920:(i+1)*10920]) 163 | print (len(listOfSubTables)) 164 | 165 | #myKernSubTable.coverage = 1 166 | #myKernSubTable.format = 0 167 | #myKernSubTable.version = 0 168 | #myKernTable.kernTables = [myKernSubTable] 169 | #myKernTable.version = 0 170 | 171 | self.addKernSubTables(myKernTable, listOfSubTables) 172 | 173 | tt['kern'] = myKernTable 174 | tt.save(fontpath_kern) 175 | remove(self.fontpath) 176 | rename(fontpath_kern, self.fontpath) 177 | 178 | def addKernSubTables(self, myKernTable, listOfSubTables): 179 | myKernTable.kernTables = [] 180 | for subTable in listOfSubTables: 181 | myKernSubTable = ttLib.tables._k_e_r_n.KernTable_format_0() 182 | myKernSubTable.kernTable = {} 183 | myKernSubTable.coverage = 1 184 | myKernSubTable.format = 0 185 | myKernSubTable.version = 0 186 | 187 | for kernPair in subTable: 188 | pair = kernPair[0] 189 | value = kernPair[1] 190 | myKernSubTable[pair] = value 191 | 192 | myKernTable.kernTables.append(myKernSubTable) 193 | 194 | 195 | 196 | def parseKerning(self, f, kerningItems): 197 | allKerning = [] 198 | for (pair, value) in kerningItems: 199 | if self.expandKern == True: 200 | if pair[0][:1] == '@' and pair[1][:1] == '@': 201 | #print 'Left and Right are groups' 202 | for c_keyLeft in f.groups.keys(): 203 | if c_keyLeft == pair[0]: 204 | #print f.groups[c_keyLeft] 205 | for gLeftname in f.groups[c_keyLeft]: 206 | for c_keyRight in f.groups.keys(): 207 | if c_keyRight == pair[1]: 208 | #print f.groups[c_keyRight] 209 | for gRightname in f.groups[c_keyRight]: 210 | processedpair = (gLeftname, gRightname) 211 | allKerning.append((processedpair, value)) 212 | 213 | elif pair[1][:1] == '@': 214 | #print 'Right only is group' 215 | for c_keyRight in f.groups.keys(): 216 | if c_keyRight == pair[1]: 217 | #print f.groups[c_keyRight] 218 | for gname in f.groups[c_keyRight]: 219 | processedpair = (pair[0], gname) 220 | allKerning.append((processedpair, value)) 221 | 222 | elif pair[0][:1] == '@': 223 | #print 'Left only is group' 224 | for c_keyLeft in f.groups.keys(): 225 | if c_keyLeft == pair[0]: 226 | #print f.groups[c_keyLeft] 227 | for gname in f.groups[c_keyLeft]: 228 | processedpair = (gname, pair[1]) 229 | allKerning.append((processedpair, value)) 230 | 231 | else: 232 | #print 'none is group' 233 | allKerning.append((pair, value)) 234 | 235 | else: 236 | #Do not expand group kerning, just use first item of group 237 | if pair[0][:1] == '@' and pair[1][:1] == '@': 238 | #print 'Left and Right are groups' 239 | for c_keyLeft in f.groups.keys(): 240 | if c_keyLeft == pair[0]: 241 | #print f.groups[c_keyLeft] 242 | for c_keyRight in f.groups.keys(): 243 | if c_keyRight == pair[1]: 244 | #print f.groups[c_keyRight] 245 | processedpair = (f.groups[c_keyLeft][0], f.groups[c_keyRight][0]) 246 | allKerning.append((processedpair, value)) 247 | 248 | elif pair[1][:1] == '@': 249 | #print 'Right only is group' 250 | for c_keyRight in f.groups.keys(): 251 | if c_keyRight == pair[1]: 252 | #print f.groups[c_keyRight] 253 | processedpair = (pair[0], f.groups[c_keyRight][0]) 254 | allKerning.append((processedpair, value)) 255 | 256 | elif pair[0][:1] == '@': 257 | #print 'Left only is group' 258 | for c_keyLeft in f.groups.keys(): 259 | if c_keyLeft == pair[0]: 260 | #print f.groups[c_keyLeft] 261 | processedpair = (f.groups[c_keyLeft][0], pair[1]) 262 | allKerning.append((processedpair, value)) 263 | 264 | else: 265 | #print 'none is group' 266 | allKerning.append((pair, value)) 267 | 268 | return allKerning 269 | 270 | 271 | 272 | f = CurrentFont() 273 | af = AllFonts() 274 | GenerateWindow() -------------------------------------------------------------------------------- /GlyphIntegrityCheck/GlyphIntegrityCheck.py: -------------------------------------------------------------------------------- 1 | from vanilla import * 2 | from defconAppKit.windows.baseWindow import BaseWindowController 3 | 4 | 5 | class Process(BaseWindowController): 6 | 7 | def __init__(self): 8 | self.w = FloatingWindow((310, 170)) 9 | self.w.textBox = TextBox((10, 10, -10, 16), "Glyphs Integrity Check", sizeStyle = "regular", alignment = "center") 10 | self.w.checkBoxMixedContours = CheckBox((10, 40, -10, 20), "Mixed Contours and Components", sizeStyle = "small", 11 | callback=self.checkBoxMixedContoursCallback, value = False) 12 | self.w.checkBoxOverlappingComponents = CheckBox((10, 70, -10, 20), "Overlapping Components", sizeStyle = "small", 13 | callback=self.checkBoxOverlappingComponentsCallback, value = False) 14 | self.w.checkBoxOverlap = CheckBox((10, 100, -10, 20), "Overlapping Contours", sizeStyle = "small", 15 | callback=self.checkBoxOverlapCallback, value = False) 16 | self.w.buttonCheck = Button((10, -20, 190, 15), "Check", sizeStyle = "small", callback=self.showProgress) 17 | self.w.buttonClose = Button((210, -20, 90, 15), "Close", sizeStyle = "small", callback=self.closeWindow) 18 | self.w.center() 19 | self.w.open() 20 | 21 | def closeWindow(self, sender): 22 | self.w.close() 23 | 24 | def checkBoxMixedContoursCallback(self, sender): 25 | sender.get() 26 | # self.w.checkBoxOverlappingComponents.set(False) 27 | # self.w.checkBoxOverlap.set(False) 28 | 29 | def checkBoxOverlappingComponentsCallback(self, sender): 30 | sender.get() 31 | # self.w.checkBoxMixedContours.set(False) 32 | # self.w.checkBoxOverlap.set(False) 33 | 34 | def checkBoxOverlapCallback(self, sender): 35 | sender.get() 36 | # self.w.checkBoxMixedContours.set(False) 37 | # self.w.checkBoxOverlappingComponents.set(False) 38 | 39 | def showProgress(self, sender): 40 | if self.w.checkBoxMixedContours.get(): 41 | self.progress = self.startProgress("Checking Mixed...") 42 | self.checkMixedContours(f) 43 | self.progress.close() 44 | 45 | if self.w.checkBoxOverlappingComponents.get(): 46 | self.progress = self.startProgress("Checking Overlapping Components...") 47 | self.checkOverlappingComponents(f) 48 | self.progress.close() 49 | 50 | if self.w.checkBoxOverlap.get(): 51 | self.progress = self.startProgress("Checking Overlapping contours...") 52 | self.checkOverlap(f) 53 | self.progress.close() 54 | self.w.close() 55 | 56 | def checkMixedContours(self, f): 57 | self.progress.setTickCount(len(f)) 58 | print '-----------------------------------' 59 | print 'Mixed Contours and Composite Report' 60 | print '-----------------------------------' 61 | for g in f: 62 | self.progress.update() 63 | if g.components: 64 | if len(g) > 0: 65 | print g.name, 'has mixed contour and composite' 66 | g.mark = (0.5, 0, 0, 0.4) 67 | f.update() 68 | 69 | def checkOverlappingComponents(self, f): 70 | self.progress.setTickCount(len(f)) 71 | print '----------------------------' 72 | print 'Overlapping Components Report' 73 | print '----------------------------' 74 | for g in f: 75 | self.progress.update() 76 | if g.components: 77 | pDM_list = [] 78 | pD_list = [] 79 | g.getLayer("_backupDecMerg").clear() 80 | g.copyToLayer("_backupDecMerg") 81 | g.getLayer("_backupDec").clear() 82 | g.copyToLayer("_backupDec") 83 | gDecomposedMerged = g.getLayer("_backupDecMerg") 84 | gDecomposed = g.getLayer("_backupDec") 85 | for cp in gDecomposedMerged.components: 86 | gDecomposedMerged.decompose() 87 | gDecomposed.decompose() 88 | gDecomposedMerged.removeOverlap() 89 | #if len(gDecomposedMerged) != len(gDecomposed): 90 | for cDM_index in range(len(gDecomposedMerged)): 91 | for i in range(len(gDecomposedMerged[cDM_index])): 92 | pDM_list.append(i) 93 | for cD_index in range(len(gDecomposed)): 94 | for i in range(len(gDecomposed[cD_index])): 95 | pD_list.append(i) 96 | if len(pDM_list) != len(pD_list) or len(gDecomposedMerged) != len(gDecomposed): 97 | print g.name, 'has overlapping components' 98 | g.mark = (0.5, 0, 0, 0.4) 99 | f.removeLayer("_backupDecMerg") 100 | f.removeLayer("_backupDec") 101 | f.update() 102 | 103 | def checkOverlap(self, f): 104 | self.progress.setTickCount(len(f)) 105 | print '--------------------------' 106 | print 'Overlapping Contours Report' 107 | print '--------------------------' 108 | for g in f: 109 | self.progress.update() 110 | pg_List = [] 111 | pgMerged_List = [] 112 | g.getLayer("_backupMerged").clear() 113 | g.copyToLayer("_backupMerged") 114 | gMerged = g.getLayer("_backupMerged") 115 | gMerged.removeOverlap() 116 | for i in range(len(g)): 117 | for j in range(len(g[i])): 118 | pg_List.append(j) 119 | for i in range(len(gMerged)): 120 | for j in range(len(gMerged[i])): 121 | pgMerged_List.append(j) 122 | if len(pg_List) != len(pgMerged_List): 123 | print g.name, 'has overlapping contours' 124 | g.mark = (0.5, 0, 0, 0.4) 125 | 126 | f.removeLayer("_backupMerged") 127 | f.update() 128 | 129 | 130 | f = CurrentFont() 131 | Process() 132 | -------------------------------------------------------------------------------- /Interpolate/Interpolate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf8 -*- 2 | from vanilla import * 3 | 4 | af = AllFonts() 5 | f = CurrentFont() 6 | 7 | 8 | def createFontList(): 9 | fontList = [] 10 | for f in af: 11 | if f.info.familyName and f.info.styleName: 12 | if f.info.styleName == "Regular": 13 | fontList.append(f.info.familyName) 14 | else: 15 | fontList.append(f.info.familyName + " " + f.info.styleName) 16 | else: 17 | return 18 | return fontList 19 | 20 | class InterpolateWindow(object): 21 | 22 | def __init__(self): 23 | self.selectedGlyphSet = '' 24 | selectedList = [] 25 | for g in f: 26 | if g.selected: 27 | selectedList.append(g.name) 28 | selectedList.sort() 29 | for e in selectedList: 30 | self.selectedGlyphSet += e + ' ' 31 | 32 | self.fontSourceName = fontList[0] 33 | self.fontTargetName = fontList[0] 34 | self.fontSourceIndex = 0 35 | self.fontTargetIndex = 0 36 | self.interpolateXValue = 0 37 | self.interpolateYValue = 0 38 | self.scaleXValue = 100 39 | self.scaleYValue = 100 40 | self.keepStrokeXValue = 100 41 | self.keepStrokeYValue = 100 42 | self.currentFont = af[self.fontSourceIndex] 43 | self.selectedGlyphSetIndex = 0 44 | self.savedGlyphSets = {} 45 | for c_Font in af: 46 | if "GlyphSets" in c_Font.lib: 47 | for i in c_Font.lib["GlyphSets"]: 48 | self.savedGlyphSets[i] = c_Font.lib["GlyphSets"][i] 49 | else: 50 | #print "no saved glyph sets" 51 | #self.savedGlyphSets = {} 52 | c_Font.lib["GlyphSets"] = {} 53 | for glyphSet in self.savedGlyphSets.keys(): 54 | c_Font.lib["GlyphSets"][glyphSet] = self.savedGlyphSets[glyphSet] 55 | 56 | if len(af[self.fontSourceIndex].info.postscriptStemSnapV) != 0: 57 | self.sourceRefX = af[self.fontSourceIndex].info.postscriptStemSnapV[0] 58 | else: 59 | self.sourceRefX = 0 60 | if len(af[self.fontSourceIndex].info.postscriptStemSnapH) != 0: 61 | self.sourceRefY = af[self.fontSourceIndex].info.postscriptStemSnapH[0] 62 | else: 63 | self.sourceRefY = 0 64 | 65 | if len(af[self.fontTargetIndex].info.postscriptStemSnapV) != 0: 66 | self.targetRefX = af[self.fontTargetIndex].info.postscriptStemSnapV[0] 67 | else: 68 | self.targetRefX = 0 69 | if len(af[self.fontTargetIndex].info.postscriptStemSnapH) != 0: 70 | self.targetRefY = af[self.fontTargetIndex].info.postscriptStemSnapH[0] 71 | else: 72 | self.targetRefY = 0 73 | 74 | self.sourceLayerList = af[self.fontSourceIndex].layerOrder 75 | self.targetLayerList = af[self.fontTargetIndex].layerOrder 76 | if len(self.sourceLayerList) > 0: 77 | self.sourceLayerName = self.sourceLayerList[0] 78 | else: 79 | self.sourceLayerName = "foreground" 80 | if len(self.targetLayerList) > 0: 81 | self.targetLayerName = self.targetLayerList[0] 82 | else: 83 | self.targetLayerName = "foreground" 84 | self.useSourceLayer = False 85 | self.useTargetLayer = False 86 | self.keepStrokeX = True 87 | self.keepStrokeY = True 88 | self.limitGlyphSet = False 89 | 90 | self.w = FloatingWindow((500, 600), "Interpolate") 91 | self.w.textBoxSource = TextBox((10, 10, 190, 20), "First Master") 92 | self.w.popUpButtonSource = PopUpButton((10, 30, 190, 20), fontList, callback=self.popUpButtonSourceCallback, sizeStyle = "regular") 93 | 94 | self.w.textBoxSourceLayer = TextBox((210, 10, 150, 20), "Layer") 95 | self.w.popUpButtonSourceLayer = PopUpButton((210, 30, 150, 20), self.sourceLayerList, callback=self.popUpButtonSourceLayerCallback, sizeStyle = "regular") 96 | self.w.textBoxSourceLayer.show(self.useSourceLayer) 97 | self.w.popUpButtonSourceLayer.show(self.useSourceLayer) 98 | 99 | self.w.textBoxSourceRefX = TextBox((370, 10, 50, 20), "Stem X") 100 | self.w.textBoxSourceRefY = TextBox((425, 10, 50, 20), "Stem Y") 101 | self.w.sourceRefXEditText = EditText((370, 30, 45, 20), 102 | callback=self.sourceRefXEditTextCallback) 103 | self.w.sourceRefYEditText = EditText((425, 30, 45, 20), 104 | callback=self.sourceRefYEditTextCallback) 105 | 106 | self.w.foregroundSourceCheckBox = CheckBox((10, 50, 150, 20), "Use Layer", 107 | callback=self.foregroundSourceCheckBoxCallback, value=self.useSourceLayer) 108 | 109 | self.w.textBoxTarget = TextBox((10, 70, 190, 20), "Second Master") 110 | self.w.popUpButtonTarget = PopUpButton((10, 90, 190, 20), fontList, callback=self.popUpButtonTargetCallback, sizeStyle = "regular") 111 | 112 | self.w.textBoxTargetLayer = TextBox((210, 70, -10, 20), "Layer") 113 | self.w.popUpButtonTargetLayer = PopUpButton((210, 90, 150, 20), self.targetLayerList, callback=self.popUpButtonTargetLayerCallback, sizeStyle = "regular") 114 | self.w.textBoxTargetLayer.show(self.useTargetLayer) 115 | self.w.popUpButtonTargetLayer.show(self.useTargetLayer) 116 | 117 | self.w.textBoxTargetRefX = TextBox((370, 70, 50, 20), "Stem X") 118 | self.w.textBoxTargetRefY = TextBox((425, 70, 50, 20), "Stem Y") 119 | self.w.targetRefXEditText = EditText((370, 90, 45, 20), 120 | callback=self.targetRefXEditTextCallback) 121 | self.w.targetRefYEditText = EditText((425, 90, 45, 20), 122 | callback=self.targetRefYEditTextCallback) 123 | 124 | self.w.foregroundTargetCheckBox = CheckBox((10, 110, 150, 20), "Use Layer", 125 | callback=self.foregroundTargetCheckBoxCallback, value=self.useTargetLayer) 126 | 127 | self.w.interpolateXTextBox = TextBox((10, 150, -10, 20), u"Interpolate X (‰)") 128 | self.w.interpolateXEditText = EditText((120, 150, 60, 20), 129 | callback=self.interpolateXEditTextCallback) 130 | self.w.resultingStemXTextBox = TextBox((190, 150, -10, 20), u"Result Stem X (FU)") 131 | self.w.resultingStemXEditText = EditText((310, 150, 60, 20), 132 | callback=self.resultingStemXEditTextCallback) 133 | self.w.interpolateXSlider = Slider((10, 180, -10, 23), 134 | tickMarkCount=7, 135 | value = 0, 136 | maxValue = 2000, 137 | minValue = -1000, 138 | callback=self.interpolateXSliderCallback) 139 | 140 | self.w.interpolateYTextBox = TextBox((10, 210, -10, 20), u"Interpolate Y (‰)") 141 | self.w.interpolateYEditText = EditText((120, 210, 60, 20), 142 | callback=self.interpolateYEditTextCallback) 143 | self.w.resultingStemYTextBox = TextBox((190, 210, -10, 20), u"Result Stem Y (FU)") 144 | self.w.resultingStemYEditText = EditText((310, 210, 60, 20), 145 | callback=self.resultingStemYEditTextCallback) 146 | self.w.interpolateYSlider = Slider((10, 240, -10, 23), 147 | tickMarkCount=7, 148 | value = 0, 149 | maxValue = 2000, 150 | minValue = -1000, 151 | callback=self.interpolateYSliderCallback) 152 | 153 | self.w.scaleXTextBox = TextBox((10, 290, -10, 20), "Scale X (%)") 154 | self.w.scaleXEditText = EditText((100, 290, 60, 20), 155 | callback=self.scaleXEditTextCallback) 156 | self.w.keepStrokeXCheckBox = CheckBox((170, 290, 200, 20), "keep stem (%)", 157 | callback=self.keepStrokeXCheckBoxCallback, value=self.keepStrokeX) 158 | self.w.keepStrokeXEditText = EditText((280, 290, 40, 20), 159 | callback=self.keepStrokeXEditTextCallback) 160 | self.w.keepStrokeXSlider = Slider((330, 290, -10, 23), 161 | value = 100, 162 | maxValue = 100, 163 | minValue = 0, 164 | callback=self.keepStrokeXSliderCallback) 165 | 166 | self.w.scaleXSlider = Slider((10, 320, -10, 23), 167 | tickMarkCount=5, 168 | value = 100, 169 | maxValue = 200, 170 | minValue = 1, 171 | callback=self.scaleXSliderCallback) 172 | 173 | self.w.scaleYTextBox = TextBox((10, 360, -10, 20), "Scale Y (%)") 174 | self.w.scaleYEditText = EditText((100, 360, 60, 20), 175 | callback=self.scaleYEditTextCallback) 176 | self.w.keepStrokeYCheckBox = CheckBox((170, 360, 200, 20), "keep stem (%)", 177 | callback=self.keepStrokeYCheckBoxCallback, value=self.keepStrokeY) 178 | self.w.keepStrokeYEditText = EditText((280, 360, 40, 20), 179 | callback=self.keepStrokeYEditTextCallback) 180 | self.w.keepStrokeYSlider = Slider((330, 360, -10, 23), 181 | value = 100, 182 | maxValue = 100, 183 | minValue = 0, 184 | callback=self.keepStrokeYSliderCallback) 185 | 186 | 187 | self.w.scaleYSlider = Slider((10, 390, -10, 23), 188 | tickMarkCount=5, 189 | value = 100, 190 | maxValue = 200, 191 | minValue = 1, 192 | callback=self.scaleYSliderCallback) 193 | 194 | self.w.glyphSetCheckBox = CheckBox((10, 420, 200, 20), "Limit to Glyphs:", 195 | callback=self.glyphSetCheckBoxCallback, value=self.limitGlyphSet) 196 | self.w.popUpButtonGlyphSet = PopUpButton((210, 420, 180, 20), self.savedGlyphSets.keys(), callback=self.popUpButtonGlyphSetCallback, sizeStyle = "regular") 197 | self.w.buttonClearGlyphSet = Button((400, 420, -10, 20), "Clear Set", 198 | callback=self.buttonClearGlyphSetCallback) 199 | self.w.glyphSetTextEditor = TextEditor((10, 450, -10, 50), 200 | callback=self.glyphSetTextEditorCallback) 201 | 202 | self.w.glyphSetTextEditor.set(self.selectedGlyphSet) 203 | 204 | self.w.buttonSaveGlyphSet = Button((10, 510, 200, 20), "Save Glyph Set As", 205 | callback=self.buttonSaveGlyphSetCallback) 206 | self.w.saveGlyphSetEditText = EditText((220, 510, -10, 20), 207 | callback=self.saveGlyphSetEditTextCallback) 208 | 209 | self.w.bar = ProgressBar((10, -60, -10, 16), sizeStyle='small') 210 | 211 | self.fontSourceList = self.w.popUpButtonSource.getItems() 212 | self.fontTargetList = self.w.popUpButtonTarget.getItems() 213 | 214 | self.w.buttonOK = Button((10, -30, 90, -10), "Apply", 215 | callback=self.buttonOKCallback) 216 | self.w.buttonNew = Button((110, -30, 200, -10), "Apply in New Font", 217 | callback=self.buttonNewCallback) 218 | self.w.buttonCancel = Button((320, -30, -10, -10), "Close", 219 | callback=self.buttonCancelCallback) 220 | 221 | self.w.interpolateXEditText.set(self.interpolateXValue) 222 | self.w.interpolateYEditText.set(self.interpolateYValue) 223 | self.w.scaleXEditText.set(self.scaleXValue) 224 | self.w.scaleYEditText.set(self.scaleYValue) 225 | 226 | self.w.keepStrokeXEditText.set(self.keepStrokeXValue) 227 | self.w.keepStrokeYEditText.set(self.keepStrokeYValue) 228 | 229 | self.w.sourceRefXEditText.set(self.sourceRefX) 230 | self.w.sourceRefYEditText.set(self.sourceRefY) 231 | self.w.targetRefXEditText.set(self.targetRefX) 232 | self.w.targetRefYEditText.set(self.targetRefY) 233 | 234 | self.w.center() 235 | self.w.open() 236 | 237 | def resetAll(self): 238 | self.w.interpolateXEditText.set(0) 239 | self.w.interpolateYEditText.set(0) 240 | self.w.scaleXEditText.set(100) 241 | self.w.scaleYEditText.set(100) 242 | self.w.interpolateXSlider.set(0) 243 | self.w.interpolateYSlider.set(0) 244 | self.w.scaleXSlider.set(100) 245 | self.w.scaleYSlider.set(100) 246 | self.w.resultingStemXEditText.set(0) 247 | self.w.resultingStemYEditText.set(0) 248 | 249 | self.interpolateXValue = 0 250 | self.interpolateYValue = 0 251 | self.scaleXValue = 100 252 | self.scaleYValue = 100 253 | self.keepStrokeXValue = 100 254 | self.keepStrokeYValue = 100 255 | 256 | def calculateResultingStem(self, minStem, maxStem, value): 257 | if maxStem-minStem != 0: 258 | return int(value/(1000.0/(maxStem-minStem))+minStem) 259 | return 0 260 | 261 | def calculateInterpolatValueFromResultingStem(self, minStem, maxStem, result): 262 | if maxStem-minStem != 0: 263 | return int((result-minStem)*(1000.0/(maxStem-minStem))) 264 | return 0 265 | 266 | def keepStrokeXEditTextCallback(self, sender): 267 | try: 268 | newValue = int(sender.get()) 269 | except ValueError: 270 | newValue = 0 271 | sender.set(0) 272 | self.keepStrokeXValue = newValue 273 | self.w.keepStrokeXSlider.set(newValue) 274 | self.setInterpolateX() 275 | 276 | def keepStrokeYEditTextCallback(self, sender): 277 | try: 278 | newValue = int(sender.get()) 279 | except ValueError: 280 | newValue = 0 281 | sender.set(0) 282 | self.keepStrokeYValue = newValue 283 | self.w.keepStrokeYSlider.set(newValue) 284 | self.setInterpolateY() 285 | 286 | def keepStrokeXSliderCallback(self, sender): 287 | self.keepStrokeXValue = int(sender.get()) 288 | self.w.keepStrokeXEditText.set(self.keepStrokeXValue) 289 | self.setInterpolateX() 290 | 291 | def keepStrokeYSliderCallback(self, sender): 292 | self.keepStrokeYValue = int(sender.get()) 293 | self.w.keepStrokeYEditText.set(self.keepStrokeYValue) 294 | self.setInterpolateY() 295 | 296 | def buttonClearGlyphSetCallback(self, sender): 297 | if len(self.savedGlyphSets.keys()) > 0: 298 | #print self.selectedGlyphSetIndex 299 | #print self.savedGlyphSets.keys() 300 | currentsavedGlyphSet = self.savedGlyphSets.keys()[self.selectedGlyphSetIndex] 301 | for c_Font in af: 302 | #print 'delete', currentsavedGlyphSet 303 | if currentsavedGlyphSet in c_Font.lib["GlyphSets"]: 304 | del c_Font.lib["GlyphSets"][str(currentsavedGlyphSet)] 305 | self.savedGlyphSets = c_Font.lib["GlyphSets"] 306 | self.w.popUpButtonGlyphSet.setItems(self.savedGlyphSets.keys()) 307 | self.w.glyphSetTextEditor.set('') 308 | self.selectedGlyphSetIndex = 0 309 | 310 | def popUpButtonGlyphSetCallback(self, sender): 311 | self.selectedGlyphSetIndex = sender.get() 312 | self.currentFont = af[self.fontSourceIndex] 313 | savedglyphSetsList = self.savedGlyphSets.keys() 314 | #print savedglyphSetsList[sender.get()] 315 | content = self.savedGlyphSets[savedglyphSetsList[sender.get()]] 316 | #print content 317 | self.w.glyphSetTextEditor.set(str(content)) 318 | self.selectedGlyphSetIndex 319 | self.selectedGlyphSet = str(content) 320 | 321 | def buttonSaveGlyphSetCallback(self, sender): 322 | self.currentFont = af[self.fontSourceIndex] 323 | newGlyphSetName = self.w.saveGlyphSetEditText.get() 324 | newGlyphSet = self.selectedGlyphSet 325 | for c_Font in af: 326 | if newGlyphSetName != '' and newGlyphSet != '': 327 | c_Font.lib["GlyphSets"][newGlyphSetName] = newGlyphSet 328 | self.savedGlyphSets[newGlyphSetName] = newGlyphSet 329 | savedglyphSetsList = self.savedGlyphSets.keys() 330 | self.w.popUpButtonGlyphSet.setItems(savedglyphSetsList) 331 | 332 | 333 | def saveGlyphSetEditTextCallback(self, sender): 334 | self.w.saveGlyphSetEditText.set(sender.get()) 335 | 336 | def glyphSetTextEditorCallback(self, sender): 337 | self.selectedGlyphSet = sender.get() 338 | self.w.glyphSetCheckBox.set(True) 339 | self.limitGlyphSet = True 340 | 341 | def glyphSetCheckBoxCallback(self, sender): 342 | self.limitGlyphSet = sender.get() 343 | 344 | def keepStrokeXCheckBoxCallback(self, sender): 345 | self.keepStrokeX = sender.get() 346 | if self.keepStrokeX: 347 | self.setInterpolateX() 348 | 349 | def keepStrokeYCheckBoxCallback(self, sender): 350 | self.keepStrokeY = sender.get() 351 | if self.keepStrokeY: 352 | self.setInterpolateY() 353 | 354 | def foregroundSourceCheckBoxCallback(self, sender): 355 | self.w.popUpButtonSourceLayer.show(sender.get()) 356 | self.w.textBoxSourceLayer.show(sender.get()) 357 | self.useSourceLayer = sender.get() 358 | 359 | def foregroundTargetCheckBoxCallback(self, sender): 360 | self.w.popUpButtonTargetLayer.show(sender.get()) 361 | self.w.textBoxTargetLayer.show(sender.get()) 362 | self.useTargetLayer = sender.get() 363 | 364 | def interpolateXSliderCallback(self, sender): 365 | #print "slider edit!", sender.get() 366 | self.interpolateXValue = int(sender.get()) 367 | self.w.interpolateXEditText.set(self.interpolateXValue) 368 | stemX = self.calculateResultingStem(self.sourceRefX, self.targetRefX, self.interpolateXValue) 369 | self.w.resultingStemXEditText.set(stemX) 370 | 371 | def interpolateYSliderCallback(self, sender): 372 | self.interpolateYValue = int(sender.get()) 373 | self.w.interpolateYEditText.set(self.interpolateYValue) 374 | stemY = self.calculateResultingStem(self.sourceRefY, self.targetRefY, self.interpolateYValue) 375 | self.w.resultingStemYEditText.set(stemY) 376 | 377 | def setInterpolateX(self): 378 | if self.keepStrokeX: 379 | if self.sourceRefX != self.targetRefX: 380 | interpolXValue = (self.keepStrokeXValue/100) * (1000*(self.sourceRefX *(100-self.scaleXValue)) / ((self.targetRefX - self.sourceRefX) * self.scaleXValue)) 381 | else: 382 | interpolXValue = 0 383 | self.interpolateXValue = int(interpolXValue) 384 | self.w.interpolateXEditText.set(self.interpolateXValue) 385 | self.w.interpolateXSlider.set(self.interpolateXValue) 386 | 387 | def setInterpolateY(self): 388 | if self.keepStrokeY: 389 | if self.sourceRefY != self.targetRefY: 390 | interpolYValue = (self.keepStrokeYValue/100) * (1000*(self.sourceRefY *(100-self.scaleYValue)) / ((self.targetRefY - self.sourceRefY) * self.scaleYValue)) 391 | else: 392 | interpolYValue = 0 393 | self.interpolateYValue = int(interpolYValue) 394 | self.w.interpolateYEditText.set(self.interpolateYValue) 395 | self.w.interpolateYSlider.set(self.interpolateYValue) 396 | 397 | def scaleXSliderCallback(self, sender): 398 | self.scaleXValue = float(sender.get()) 399 | self.w.scaleXEditText.set(self.scaleXValue) 400 | self.setInterpolateX() 401 | 402 | 403 | def scaleYSliderCallback(self, sender): 404 | self.scaleYValue = float(sender.get()) 405 | self.w.scaleYEditText.set(self.scaleYValue) 406 | self.setInterpolateY() 407 | 408 | 409 | def popUpButtonSourceCallback(self, sender): 410 | self.resetAll() 411 | self.fontSourceIndex = sender.get() 412 | self.fontSourceName = self.fontSourceList[sender.get()] 413 | self.w.popUpButtonSourceLayer.setItems(af[self.fontSourceIndex].layerOrder) 414 | self.sourceLayerList = af[self.fontSourceIndex].layerOrder 415 | if len(self.sourceLayerList) > 0: 416 | self.sourceLayerName = self.sourceLayerList[0] 417 | else: 418 | self.sourceLayerName = "foreground" 419 | if len(af[self.fontSourceIndex].info.postscriptStemSnapV) != 0: 420 | self.sourceRefX = af[self.fontSourceIndex].info.postscriptStemSnapV[0] 421 | else: 422 | self.sourceRefX = 0 423 | self.w.sourceRefXEditText.set(self.sourceRefX) 424 | if len(af[self.fontSourceIndex].info.postscriptStemSnapH) != 0: 425 | self.sourceRefY = af[self.fontSourceIndex].info.postscriptStemSnapH[0] 426 | else: 427 | self.sourceRefY = 0 428 | self.w.sourceRefYEditText.set(self.sourceRefY) 429 | 430 | def popUpButtonTargetCallback(self, sender): 431 | self.resetAll() 432 | self.fontTargetIndex = sender.get() 433 | self.fontTargetName = self.fontTargetList[sender.get()] 434 | self.w.popUpButtonTargetLayer.setItems(af[self.fontTargetIndex].layerOrder) 435 | self.targetLayerList = af[self.fontTargetIndex].layerOrder 436 | if len(self.targetLayerList) > 0: 437 | self.targetLayerName = self.targetLayerList[0] 438 | else: 439 | self.targetLayerName = "foreground" 440 | if len(af[self.fontTargetIndex].info.postscriptStemSnapV) != 0: 441 | self.targetRefX = af[self.fontTargetIndex].info.postscriptStemSnapV[0] 442 | else: 443 | self.targetRefX = 0 444 | self.w.targetRefXEditText.set(self.targetRefX) 445 | if len(af[self.fontTargetIndex].info.postscriptStemSnapH) != 0: 446 | self.targetRefY = af[self.fontTargetIndex].info.postscriptStemSnapH[0] 447 | else: 448 | self.targetRefY = 0 449 | self.w.targetRefYEditText.set(self.targetRefY) 450 | 451 | 452 | def popUpButtonSourceLayerCallback(self, sender): 453 | self.sourceLayerIndex = sender.get() 454 | self.sourceLayerName = self.sourceLayerList[self.sourceLayerIndex] 455 | 456 | def popUpButtonTargetLayerCallback(self, sender): 457 | self.targetLayerIndex = sender.get() 458 | self.targetLayerName = self.targetLayerList[self.targetLayerIndex] 459 | 460 | def isInteger(self, string): 461 | try: 462 | return int(string) 463 | except ValueError: 464 | return 0 465 | 466 | def sourceRefXEditTextCallback(self, sender): 467 | try: 468 | newValue = int(sender.get()) 469 | except ValueError: 470 | newValue = 0 471 | sender.set(0) 472 | self.sourceRefX = newValue 473 | 474 | def sourceRefYEditTextCallback(self, sender): 475 | try: 476 | newValue = int(sender.get()) 477 | except ValueError: 478 | newValue = 0 479 | sender.set(0) 480 | self.sourceRefY = newValue 481 | 482 | def targetRefXEditTextCallback(self, sender): 483 | try: 484 | newValue = int(sender.get()) 485 | except ValueError: 486 | newValue = 0 487 | sender.set(0) 488 | self.targetRefX = newValue 489 | 490 | def targetRefYEditTextCallback(self, sender): 491 | try: 492 | newValue = int(sender.get()) 493 | except ValueError: 494 | newValue = 0 495 | sender.set(0) 496 | self.targetRefY = newValue 497 | 498 | def interpolateXEditTextCallback(self, sender): 499 | try: 500 | newValue = int(sender.get()) 501 | except ValueError: 502 | if sender.get() == '-': 503 | newValue = 0 504 | else: 505 | newValue = 0 506 | sender.set(0) 507 | self.w.interpolateXSlider.set(newValue) 508 | self.interpolateXValue = newValue 509 | stemX = self.calculateResultingStem(self.sourceRefX, self.targetRefX, self.interpolateXValue) 510 | self.w.resultingStemXEditText.set(stemX) 511 | 512 | def interpolateYEditTextCallback(self, sender): 513 | try: 514 | newValue = int(sender.get()) 515 | except ValueError: 516 | if sender.get() == '-': 517 | newValue = 0 518 | else: 519 | newValue = 0 520 | sender.set(0) 521 | self.w.interpolateYSlider.set(newValue) 522 | self.interpolateYValue = newValue 523 | stemY = self.calculateResultingStem(self.sourceRefY, self.targetRefY, self.interpolateYValue) 524 | self.w.resultingStemYEditText.set(stemY) 525 | 526 | def resultingStemXEditTextCallback(self, sender): 527 | try: 528 | newValue = int(sender.get()) 529 | except ValueError: 530 | newValue = 0 531 | sender.set(0) 532 | 533 | interpolValue = self.calculateInterpolatValueFromResultingStem(self.sourceRefX, self.targetRefX, newValue) 534 | self.w.interpolateXEditText.set(interpolValue) 535 | self.w.interpolateXSlider.set(interpolValue) 536 | self.interpolateXValue = interpolValue 537 | 538 | def resultingStemYEditTextCallback(self, sender): 539 | try: 540 | newValue = int(sender.get()) 541 | except ValueError: 542 | newValue = 0 543 | sender.set(0) 544 | 545 | interpolValue = self.calculateInterpolatValueFromResultingStem(self.sourceRefY, self.targetRefY, newValue) 546 | self.w.interpolateYEditText.set(interpolValue) 547 | self.w.interpolateYSlider.set(interpolValue) 548 | self.interpolateYValue = interpolValue 549 | 550 | def scaleXEditTextCallback(self, sender): 551 | try: 552 | newValue = float(sender.get()) 553 | except ValueError: 554 | newValue = 1 555 | sender.set(1) 556 | if newValue == 0: 557 | newValue = 1 558 | sender.set(1) 559 | self.w.scaleXSlider.set(newValue) 560 | self.scaleXValue = newValue 561 | self.setInterpolateX() 562 | 563 | def scaleYEditTextCallback(self, sender): 564 | try: 565 | newValue = float(sender.get()) 566 | except ValueError: 567 | newValue = 1 568 | sender.set(1) 569 | if newValue == 0: 570 | newValue = 1 571 | sender.set(1) 572 | self.w.scaleYSlider.set(newValue) 573 | self.scaleYValue = newValue 574 | self.setInterpolateY() 575 | 576 | def findMatchingIndexes(self, componentName, gS, gT): 577 | for iS in range(len(gS.components)): 578 | for iT in range(len(gT.components)): 579 | if componentName == gS.components[iS].baseGlyph == gT.components[iT].baseGlyph: 580 | return (iS, iT) 581 | 582 | def interpol(self, gS, gT, valueX, valueY): 583 | gI = gS.copy() 584 | for i in range(len(gS)): 585 | for j in range(len(gS[i].points)): 586 | sourcePoint = self.allSourcePoints[i][j] 587 | targetPoint = self.allTargetPoints[i][j] 588 | gI[i].points[j].x = int((sourcePoint[0] + ((targetPoint[0] - sourcePoint[0]) * valueX/1000)) * self.scaleXValue/100) 589 | gI[i].points[j].y = int((sourcePoint[1] + ((targetPoint[1] - sourcePoint[1]) * valueY/1000)) * self.scaleYValue/100) 590 | if gI.components > 0: 591 | for i in range(len(gI.components)): 592 | if gS.components[i].baseGlyph == gT.components[i].baseGlyph: 593 | indexS = i 594 | indexT = i 595 | else: 596 | (indexS, indexT) = self.findMatchingIndexes(gI.components[i].baseGlyph, gS, gT) 597 | 598 | if indexS != None and indexT != None: 599 | gI.components[i].offset = ( int( (gS.components[indexS].offset[0] + ((gT.components[indexT].offset[0] - gS.components[indexS].offset[0]) * valueX/1000)) * self.scaleXValue/100 ), int( (gS.components[indexS].offset[1] + ((gT.components[indexT].offset[1] - gS.components[indexS].offset[1]) * valueX/1000)) * self.scaleXValue/100 ) ) 600 | else: 601 | print 'ERROR: components not matching' 602 | gI.width = int((gS.width + ((gT.width - gS.width) * valueX/1000)) * self.scaleXValue/100) 603 | return gI 604 | 605 | def collaPolate(self, gS, gT, barIncrement): 606 | self.w.bar.increment(barIncrement) 607 | #Collect Master1 points 608 | self.allSourcePoints = [] 609 | self.allSourcePointsLength = [] 610 | if self.useSourceLayer: 611 | sourceLayer = gS.getLayer(self.sourceLayerName) 612 | else: 613 | sourceLayer = gS 614 | 615 | for i in range(len(sourceLayer)): 616 | self.allSourcePoints.append([]) 617 | for j in range(len(sourceLayer[i].points)): 618 | 619 | self.allSourcePoints[i].append((sourceLayer[i].points[j].x, sourceLayer[i].points[j].y)) 620 | self.allSourcePointsLength.append(j) 621 | 622 | #Collect Master2 points 623 | self.allTargetPoints = [] 624 | self.allTargetPointsLength = [] 625 | if self.useTargetLayer: 626 | targetLayer = gT.getLayer(self.targetLayerName) 627 | else: 628 | targetLayer = gT 629 | 630 | for i in range(len(targetLayer)): 631 | self.allTargetPoints.append([]) 632 | for j in range(len(targetLayer[i].points)): 633 | 634 | self.allTargetPoints[i].append((targetLayer[i].points[j].x, targetLayer[i].points[j].y)) 635 | self.allTargetPointsLength.append(j) 636 | ## 637 | 638 | if self.allSourcePointsLength != self.allTargetPointsLength: 639 | print 'Warning: Glyph ' + gS.name + ' masters not matching' 640 | gS.mark = (1, 0, 0, 0.5) 641 | #print self.allSourcePoints 642 | #print self.allTargetPoints 643 | else: 644 | gI = self.interpol(gS, gT, self.interpolateXValue, self.interpolateYValue) 645 | if self.new: 646 | self.newFont.newGlyph(gI.name) 647 | self.newFont[gI.name] = gI 648 | #self.newFont[gI.name].update() 649 | else: 650 | self.sourceFont[gI.name] = gI 651 | #self.sourceFont[gI.name].update() 652 | 653 | def buttonOKCallback(self, sender): 654 | self.new = False 655 | self.w.bar.set(0) 656 | self.sourceFont = af[self.fontSourceIndex] 657 | self.targetFont = af[self.fontTargetIndex] 658 | barIncrement = 100/len(self.targetFont) 659 | for gT in self.targetFont: 660 | self.w.bar.increment(barIncrement) 661 | for gS in self.sourceFont: 662 | if gT.name == gS.name: 663 | if self.limitGlyphSet: 664 | s = str(self.selectedGlyphSet) 665 | l = s.split(' ') 666 | if gT.name in l: 667 | self.collaPolate(gS, gT, barIncrement) 668 | else: 669 | self.collaPolate(gS, gT, barIncrement) 670 | self.sourceFont.update() 671 | self.w.bar.set(0) 672 | 673 | #self.w.close() 674 | 675 | def buttonNewCallback(self, sender): 676 | self.new = True 677 | self.newFont = RFont() 678 | if len(self.newFont) != 0: 679 | barIncrement = 100/len(self.newFont) 680 | else: 681 | barIncrement = 100 682 | for g in self.newFont: 683 | if g: 684 | self.newFont.removeGlyph(g.name) 685 | self.w.bar.increment(barIncrement) 686 | self.w.bar.set(0) 687 | self.sourceFont = af[self.fontSourceIndex] 688 | self.targetFont = af[self.fontTargetIndex] 689 | 690 | barIncrement = 100/len(self.targetFont) 691 | for gT in self.targetFont: 692 | for gS in self.sourceFont: 693 | if gT.name == gS.name: 694 | if self.limitGlyphSet: 695 | s = str(self.selectedGlyphSet) 696 | l = s.split(' ') 697 | if gT.name in l: 698 | self.collaPolate(gS, gT, barIncrement) 699 | else: 700 | self.collaPolate(gS, gT, barIncrement) 701 | self.newFont.update() 702 | 703 | master1_kerning = self.sourceFont.kerning 704 | master2_kerning = self.targetFont.kerning 705 | kerning1Items = master1_kerning.items() 706 | kerning2Items = master2_kerning.items() 707 | groups1Items = self.sourceFont.groups.items() 708 | groups2Items = self.targetFont.groups.items() 709 | 710 | for (groupName1, grouppedGlyphs1) in groups1Items: 711 | for (groupName2, grouppedGlyphs2) in groups2Items: 712 | grouppedGlyphs1.sort() 713 | grouppedGlyphs2.sort() 714 | if groupName1 == groupName2 and grouppedGlyphs1 == grouppedGlyphs2: 715 | self.newFont.groups[groupName1] = grouppedGlyphs1 716 | 717 | newKerning = {} 718 | for (pair1, value1) in kerning1Items: 719 | #for (pair2, value2) in kerning2Items: 720 | if pair1 in master2_kerning: 721 | value2 = master2_kerning[pair1] 722 | interpolatedValue = int((value1 + ((value2 - value1) * self.interpolateXValue/1000.0)) * self.scaleXValue/100.0) 723 | #self.newFont.kerning[pair1] = interpolatedValue 724 | newKerning[pair1] = interpolatedValue 725 | else: 726 | interpolatedValue = int((value1 * self.interpolateXValue/1000.0) * self.scaleXValue/100.0) 727 | newKerning[pair1] = interpolatedValue 728 | for (pair2, value2) in kerning2Items: 729 | if pair2 not in master1_kerning: 730 | interpolatedValue = int( (value2 * self.interpolateXValue/1000.0) * self.scaleXValue/100.0) 731 | newKerning[pair2] = interpolatedValue 732 | 733 | self.newFont.kerning.update(newKerning) 734 | 735 | dictinfo = self.newFont.info.asDict() 736 | 737 | for elem in sorted(dictinfo.keys()): 738 | self.newFont.info.__setattr__(elem, self.sourceFont.info.__getattr__(elem)) 739 | if self.sourceFont.info.__getattr__(elem) != None: 740 | #print(str(elem) + " = " + str(self.sourceFont.info.__getattr__(elem))) 741 | if str(elem) in ["ascender", "capHeight", "descender", "xHeight", "openTypeHheaAscender", "openTypeHheaDescender", "openTypeHheaLineGap", "openTypeOS2TypoAscender", "openTypeOS2TypoDescender", "openTypeOS2TypoLineGap", "openTypeOS2WinAscent", "openTypeOS2WinDescent", ""]: 742 | source = self.sourceFont.info.__getattr__(elem) 743 | target = self.targetFont.info.__getattr__(elem) 744 | interpolated = int((source + ((target - source) * self.interpolateYValue/1000.0)) * self.scaleYValue/100.0) 745 | print str(elem), ': ', source, target, '-->', interpolated 746 | self.newFont.info.__setattr__(elem, interpolated) 747 | if str(elem) in ["postscriptBlueValues", "postscriptOtherBlues", "postscriptStemSnapH", "postscriptStemSnapV"]: 748 | source = self.sourceFont.info.__getattr__(elem) 749 | target = self.targetFont.info.__getattr__(elem) 750 | interpolatedList = [] 751 | if len(source) == len(target): 752 | for i in range(len(source)): 753 | interpolated = int((source[i] + ((target[i] - source[i]) * self.interpolateYValue/1000.0)) * self.scaleYValue/100.0) 754 | interpolatedList.append(interpolated) 755 | print str(elem), ': ', source, target, '-->', interpolatedList 756 | self.newFont.info.__setattr__(elem, interpolatedList) 757 | 758 | 759 | self.w.bar.set(0) 760 | 761 | def buttonCancelCallback(self, sender): 762 | #print "Cancel" 763 | self.w.close() 764 | 765 | 766 | fontList = createFontList() 767 | if fontList: 768 | InterpolateWindow() 769 | else: 770 | print 'All open fonts must have familyName and styleName' 771 | -------------------------------------------------------------------------------- /MakeAccents/MakeAccents.py: -------------------------------------------------------------------------------- 1 | from vanilla import * 2 | from defconAppKit.windows.baseWindow import BaseWindowController 3 | import math 4 | 5 | toBeDecomposed = [ 6 | 'AE', 'OE', 'Lslash', 'Oslash', 'Eth', 'Thorn', 7 | 'ae', 'oe', 'lslash', 'oslash', 'eth', 'thorn', 'germandbls', 8 | 'ae.sc', 'oe.sc', 'lslash.sc', 'oslash.sc', 'eth.sc', 'thorn.sc', 9 | 'fi', 'fl', 'f_f', 'f_f_i', 'f_f_l', 'f_t', 'f_b', 'f_f_b', 'f_h', 'f_f_h', 'f_k', 'f_f_k', 'f_j', 'f_f_j', 'f_f_t', 'c_t', 's_p', 's_t', 10 | 'Aogonek', 'Ccedilla', 'Eogonek', 'Hbar', 'Iogonek', 'Scedilla', 'Tbar', 'Uogonek', 11 | 'aogonek', 'ccedilla', 'dcroat', 'eogonek', 'hbar', 'iogonek', 'scedilla', 'tbar', 'uogonek', 12 | 'aogonek.sc', 'ccedilla.sc', 'eogonek.sc', 'hbar.sc', 'iogonek.sc', 'scedilla.sc', 'tbar.sc', 'uogonek.sc', 13 | ] 14 | metricsAdjust = [ 15 | 'Lcaron', 'Ldot', 16 | 'hcircumflex', 'dcaron', 'lacute', 'lcaron', 'ldot', 17 | 'lcaron.sc', 'ldot.sc', 18 | ] 19 | 20 | extrasS = { 21 | 'fi': [['f', 'i'], []], 22 | 'fl': [['f', 'l'], []], 23 | 24 | 'AE': [['A', 'E'], []], 25 | 'OE': [['O', 'E'], []], 26 | 'Lslash': [['L'], ['macron']], 27 | 'Oslash': [['O'], ['slash']], 28 | 'Eth': [['D'], ['macron']], 29 | 'Thorn': [['P'], []], 30 | 31 | 'Aacute': [['A'], ['acute']], 32 | 'Acircumflex': [['A'], ['circumflex']], 33 | 'Adieresis': [['A'], ['dieresis']], 34 | 'Agrave': [['A'], ['grave']], 35 | 'Aring': [['A'], ['ring']], 36 | 'Atilde': [['A'], ['tilde']], 37 | 'Abreve': [['A'], ['breve']], 38 | 'Amacron': [['A'], ['macron']], 39 | 'Aogonek': [['A'], ['ogonek']], 40 | 'Ccedilla': [['C'], ['cedilla']], 41 | 'Cacute': [['C'], ['acute']], 42 | 'Ccaron': [['C'], ['caron']], 43 | 'Ccircumflex': [['C'], ['circumflex']], 44 | 'Cdotaccent': [['C'], ['dotaccent']], 45 | 'Dcaron': [['D'], ['caron']], 46 | 'Dcroat': [['Eth'], []], 47 | 'Eacute': [['E'], ['acute']], 48 | 'Ecircumflex': [['E'], ['circumflex']], 49 | 'Edieresis': [['E'], ['dieresis']], 50 | 'Egrave': [['E'], ['grave']], 51 | 'Ebreve': [['E'], ['breve']], 52 | 'Ecaron': [['E'], ['caron']], 53 | 'Edotaccent': [['E'], ['dotaccent']], 54 | 'Emacron': [['E'], ['macron']], 55 | 'Eogonek': [['E'], ['ogonek']], 56 | 'Gbreve': [['G'], ['breve']], 57 | 'Gcircumflex': [['G'], ['circumflex']], 58 | 'Gcommaaccent': [['G'], ['commaaccent']], 59 | 'Gdotaccent': [['G'], ['dotaccent']], 60 | 'Hbar': [['H'], ['macron']], 61 | 'Hcircumflex': [['H'], ['circumflex']], 62 | 'Iacute': [['I'], ['acute']], 63 | 'Icircumflex': [['I'], ['circumflex']], 64 | 'Idieresis': [['I'], ['dieresis']], 65 | 'Igrave': [['I'], ['grave']], 66 | 'Ibreve': [['I'], ['breve']], 67 | 'Idotaccent': [['I'], ['dotaccent']], 68 | 'Imacron': [['I'], ['macron']], 69 | 'Iogonek': [['I'], ['ogonek']], 70 | 'Itilde': [['I'], ['tilde']], 71 | 'Jcircumflex': [['J'], ['circumflex']], 72 | 'IJ': [['I', 'J'], []], 73 | 'Kcommaaccent': [['K'], ['commaaccent']], 74 | 'Lacute': [['L'], ['acute']], 75 | 'Lcaron': [['L'], ['caron.alt']], 76 | 'Lcommaaccent': [['L'], ['commaaccent']], 77 | 'Ldot': [['L'], ['periodcentered']], 78 | 'Ntilde': [['N'], ['tilde']], 79 | 'Nacute': [['N'], ['acute']], 80 | 'Ncaron': [['N'], ['caron']], 81 | 'Ncommaaccent': [['N'], ['commaaccent']], 82 | 'Oacute': [['O'], ['acute']], 83 | 'Ocircumflex': [['O'], ['circumflex']], 84 | 'Odieresis': [['O'], ['dieresis']], 85 | 'Ograve': [['O'], ['grave']], 86 | 'Otilde': [['O'], ['tilde']], 87 | 'Obreve': [['O'], ['breve']], 88 | 'Ohungarumlaut': [['O'], ['hungarumlaut']], 89 | 'Omacron': [['O'], ['macron']], 90 | 'Racute': [['R'], ['acute']], 91 | 'Rcaron': [['R'], ['caron']], 92 | 'Rcommaaccent': [['R'], ['commaaccent']], 93 | 'Sacute': [['S'], ['acute']], 94 | 'Scaron': [['S'], ['caron']], 95 | 'Scedilla': [['S'], ['cedilla']], 96 | 'Scircumflex': [['S'], ['circumflex']], 97 | 'uni0218': [['S'], ['commaaccent']], 98 | 'Tbar': [['T'], ['macron']], 99 | 'Tcaron': [['T'], ['caron']], 100 | 'uni0162': [['T'], ['commaaccent']], 101 | 'uni021A': [['T'], ['commaaccent']], 102 | 'Uacute': [['U'], ['acute']], 103 | 'Ucircumflex': [['U'], ['circumflex']], 104 | 'Udieresis': [['U'], ['dieresis']], 105 | 'Ugrave': [['U'], ['grave']], 106 | 'Ubreve': [['U'], ['breve']], 107 | 'Uhungarumlaut': [['U'], ['hungarumlaut']], 108 | 'Umacron': [['U'], ['macron']], 109 | 'Uogonek': [['U'], ['ogonek']], 110 | 'Uring': [['U'], ['ring']], 111 | 'Utilde': [['U'], ['tilde']], 112 | 'Wacute': [['W'], ['acute']], 113 | 'Wcircumflex': [['W'], ['circumflex']], 114 | 'Wdieresis': [['W'], ['dieresis']], 115 | 'Wgrave': [['W'], ['grave']], 116 | 'Yacute': [['Y'], ['acute']], 117 | 'Ycircumflex': [['Y'], ['circumflex']], 118 | 'Ydieresis': [['Y'], ['dieresis']], 119 | 'Ygrave': [['Y'], ['grave']], 120 | 'Zcaron': [['Z'], ['caron']], 121 | 'Zacute': [['Z'], ['acute']], 122 | 'Zdotaccent': [['Z'], ['dotaccent']], 123 | 124 | 'ae': [['a', 'e'], []], 125 | 'oe': [['o', 'e'], []], 126 | 'lslash': [['l'], ['macron']], 127 | 'oslash': [['o'], ['slash']], 128 | 'eth': [['d'], ['macron']], 129 | 'thorn': [['p'], []], 130 | 'germandbls': [['f', 's'], []], 131 | 132 | 'aacute': [['a'], ['acute']], 133 | 'acircumflex': [['a'], ['circumflex']], 134 | 'adieresis': [['a'], ['dieresis']], 135 | 'agrave': [['a'], ['grave']], 136 | 'aring': [['a'], ['ring']], 137 | 'atilde': [['a'], ['tilde']], 138 | 'abreve': [['a'], ['breve']], 139 | 'amacron': [['a'], ['macron']], 140 | 'aogonek': [['a'], ['ogonek']], 141 | 'ccedilla': [['c'], ['cedilla']], 142 | 'cacute': [['c'], ['acute']], 143 | 'ccaron': [['c'], ['caron']], 144 | 'ccircumflex': [['c'], ['circumflex']], 145 | 'cdotaccent': [['c'], ['dotaccent']], 146 | 'dcaron': [['d'], ['caron.alt']], 147 | 'dcroat': [['d'], ['macron']], 148 | 'eacute': [['e'], ['acute']], 149 | 'ecircumflex': [['e'], ['circumflex']], 150 | 'edieresis': [['e'], ['dieresis']], 151 | 'egrave': [['e'], ['grave']], 152 | 'ebreve': [['e'], ['breve']], 153 | 'ecaron': [['e'], ['caron']], 154 | 'edotaccent': [['e'], ['dotaccent']], 155 | 'emacron': [['e'], ['macron']], 156 | 'eogonek': [['e'], ['ogonek']], 157 | 'gbreve': [['g'], ['breve']], 158 | 'gcircumflex': [['g'], ['circumflex']], 159 | 'gcommaaccent': [['g'], ['revcommaaccent']], 160 | 'gdotaccent': [['g'], ['dotaccent']], 161 | 'hbar': [['h'], ['macron']], 162 | 'hcircumflex': [['h'], ['circumflex']], 163 | 'iacute': [['dotlessi'], ['acute']], 164 | 'icircumflex': [['dotlessi'], ['circumflex']], 165 | 'idieresis': [['dotlessi'], ['dieresis']], 166 | 'igrave': [['dotlessi'], ['grave']], 167 | 'ibreve': [['dotlessi'], ['breve']], 168 | 'i.dot': [['i'], []], 169 | 'imacron': [['dotlessi'], ['macron']], 170 | 'iogonek': [['i'], ['ogonek']], 171 | 'itilde': [['dotlessi'], ['tilde']], 172 | 'jcircumflex': [['dotlessj'], ['circumflex']], 173 | 'ij': [['i', 'j'], []], 174 | 'kcommaaccent': [['k'], ['commaaccent']], 175 | 'lacute': [['l'], ['acute']], 176 | 'lcaron': [['l'], ['caron.alt']], 177 | 'lcommaaccent': [['l'], ['commaaccent']], 178 | 'ldot': [['l'], ['periodcentered']], 179 | 'ntilde': [['n'], ['tilde']], 180 | 'nacute': [['n'], ['acute']], 181 | 'ncaron': [['n'], ['caron']], 182 | 'ncommaaccent': [['n'], ['commaaccent']], 183 | 'oacute': [['o'], ['acute']], 184 | 'ocircumflex': [['o'], ['circumflex']], 185 | 'odieresis': [['o'], ['dieresis']], 186 | 'ograve': [['o'], ['grave']], 187 | 'otilde': [['o'], ['tilde']], 188 | 'obreve': [['o'], ['breve']], 189 | 'ohungarumlaut': [['o'], ['hungarumlaut']], 190 | 'omacron': [['o'], ['macron']], 191 | 'racute': [['r'], ['acute']], 192 | 'rcaron': [['r'], ['caron']], 193 | 'rcommaaccent': [['r'], ['commaaccent']], 194 | 'sacute': [['s'], ['acute']], 195 | 'scaron': [['s'], ['caron']], 196 | 'scedilla': [['s'], ['cedilla']], 197 | 'scircumflex': [['s'], ['circumflex']], 198 | 'uni0219': [['s'], ['commaaccent']], 199 | 'tbar': [['t'], ['macron']], 200 | 'tcaron': [['t'], ['caron.alt']], 201 | 'uni0163': [['t'], ['commaaccent']], 202 | 'uni021B': [['t'], ['commaaccent']], 203 | 'uacute': [['u'], ['acute']], 204 | 'ucircumflex': [['u'], ['circumflex']], 205 | 'udieresis': [['u'], ['dieresis']], 206 | 'ugrave': [['u'], ['grave']], 207 | 'ubreve': [['u'], ['breve']], 208 | 'uhungarumlaut': [['u'], ['hungarumlaut']], 209 | 'umacron': [['u'], ['macron']], 210 | 'uogonek': [['u'], ['ogonek']], 211 | 'uring': [['u'], ['ring']], 212 | 'utilde': [['u'], ['tilde']], 213 | 'wacute': [['w'], ['acute']], 214 | 'wcircumflex': [['w'], ['circumflex']], 215 | 'wdieresis': [['w'], ['dieresis']], 216 | 'wgrave': [['w'], ['grave']], 217 | 'yacute': [['y'], ['acute']], 218 | 'ycircumflex': [['y'], ['circumflex']], 219 | 'ydieresis': [['y'], ['dieresis']], 220 | 'ygrave': [['y'], ['grave']], 221 | 'zcaron': [['z'], ['caron']], 222 | 'zacute': [['z'], ['acute']], 223 | 'zdotaccent': [['z'], ['dotaccent']], 224 | } 225 | 226 | extrasM = { 227 | 'fi': [['f', 'i'], []], 228 | 'fl': [['f', 'l'], []], 229 | 230 | 'f_f': [['f', 'f'], []], 231 | 'f_f_i': [['f', 'f', 'i'], []], 232 | 'f_f_l': [['f', 'f', 'l'], []], 233 | 234 | 'AE': [['A', 'E'], []], 235 | 'OE': [['O', 'E'], []], 236 | 'Lslash': [['L'], ['macron']], 237 | 'Oslash': [['O'], ['slash']], 238 | 'Eth': [['D'], ['macron']], 239 | 'Thorn': [['P'], []], 240 | 241 | 'Aacute': [['A'], ['acute']], 242 | 'Acircumflex': [['A'], ['circumflex']], 243 | 'Adieresis': [['A'], ['dieresis']], 244 | 'Agrave': [['A'], ['grave']], 245 | 'Aring': [['A'], ['ring']], 246 | 'Atilde': [['A'], ['tilde']], 247 | 'Abreve': [['A'], ['breve']], 248 | 'Amacron': [['A'], ['macron']], 249 | 'Aogonek': [['A'], ['ogonek']], 250 | 'Ccedilla': [['C'], ['cedilla']], 251 | 'Cacute': [['C'], ['acute']], 252 | 'Ccaron': [['C'], ['caron']], 253 | 'Ccircumflex': [['C'], ['circumflex']], 254 | 'Cdotaccent': [['C'], ['dotaccent']], 255 | 'Dcaron': [['D'], ['caron']], 256 | 'Dcroat': [['Eth'], []], 257 | 'Eacute': [['E'], ['acute']], 258 | 'Ecircumflex': [['E'], ['circumflex']], 259 | 'Edieresis': [['E'], ['dieresis']], 260 | 'Egrave': [['E'], ['grave']], 261 | 'Ebreve': [['E'], ['breve']], 262 | 'Ecaron': [['E'], ['caron']], 263 | 'Edotaccent': [['E'], ['dotaccent']], 264 | 'Emacron': [['E'], ['macron']], 265 | 'Eogonek': [['E'], ['ogonek']], 266 | 'Gbreve': [['G'], ['breve']], 267 | 'Gcircumflex': [['G'], ['circumflex']], 268 | 'Gcommaaccent': [['G'], ['commaaccent']], 269 | 'Gdotaccent': [['G'], ['dotaccent']], 270 | 'Hbar': [['H'], ['macron']], 271 | 'Hcircumflex': [['H'], ['circumflex']], 272 | 'Iacute': [['I'], ['acute']], 273 | 'Icircumflex': [['I'], ['circumflex']], 274 | 'Idieresis': [['I'], ['dieresis']], 275 | 'Igrave': [['I'], ['grave']], 276 | 'Ibreve': [['I'], ['breve']], 277 | 'Idotaccent': [['I'], ['dotaccent']], 278 | 'Imacron': [['I'], ['macron']], 279 | 'Iogonek': [['I'], ['ogonek']], 280 | 'Itilde': [['I'], ['tilde']], 281 | 'Jcircumflex': [['J'], ['circumflex']], 282 | 'IJ': [['I', 'J'], []], 283 | 'Kcommaaccent': [['K'], ['commaaccent']], 284 | 'Lacute': [['L'], ['acute']], 285 | 'Lcaron': [['L'], ['caron.alt']], 286 | 'Lcommaaccent': [['L'], ['commaaccent']], 287 | 'Ldot': [['L'], ['periodcentered']], 288 | 'Ntilde': [['N'], ['tilde']], 289 | 'Nacute': [['N'], ['acute']], 290 | 'Ncaron': [['N'], ['caron']], 291 | 'Ncommaaccent': [['N'], ['commaaccent']], 292 | 'Oacute': [['O'], ['acute']], 293 | 'Ocircumflex': [['O'], ['circumflex']], 294 | 'Odieresis': [['O'], ['dieresis']], 295 | 'Ograve': [['O'], ['grave']], 296 | 'Otilde': [['O'], ['tilde']], 297 | 'Obreve': [['O'], ['breve']], 298 | 'Ohungarumlaut': [['O'], ['hungarumlaut']], 299 | 'Omacron': [['O'], ['macron']], 300 | 'Racute': [['R'], ['acute']], 301 | 'Rcaron': [['R'], ['caron']], 302 | 'Rcommaaccent': [['R'], ['commaaccent']], 303 | 'Sacute': [['S'], ['acute']], 304 | 'Scaron': [['S'], ['caron']], 305 | 'Scedilla': [['S'], ['cedilla']], 306 | 'Scircumflex': [['S'], ['circumflex']], 307 | 'uni0218': [['S'], ['commaaccent']], 308 | 'Tbar': [['T'], ['macron']], 309 | 'Tcaron': [['T'], ['caron']], 310 | 'uni0162': [['T'], ['commaaccent']], 311 | 'uni021A': [['T'], ['commaaccent']], 312 | 'Uacute': [['U'], ['acute']], 313 | 'Ucircumflex': [['U'], ['circumflex']], 314 | 'Udieresis': [['U'], ['dieresis']], 315 | 'Ugrave': [['U'], ['grave']], 316 | 'Ubreve': [['U'], ['breve']], 317 | 'Uhungarumlaut': [['U'], ['hungarumlaut']], 318 | 'Umacron': [['U'], ['macron']], 319 | 'Uogonek': [['U'], ['ogonek']], 320 | 'Uring': [['U'], ['ring']], 321 | 'Utilde': [['U'], ['tilde']], 322 | 'Wacute': [['W'], ['acute']], 323 | 'Wcircumflex': [['W'], ['circumflex']], 324 | 'Wdieresis': [['W'], ['dieresis']], 325 | 'Wgrave': [['W'], ['grave']], 326 | 'Yacute': [['Y'], ['acute']], 327 | 'Ycircumflex': [['Y'], ['circumflex']], 328 | 'Ydieresis': [['Y'], ['dieresis']], 329 | 'Ygrave': [['Y'], ['grave']], 330 | 'Zcaron': [['Z'], ['caron']], 331 | 'Zacute': [['Z'], ['acute']], 332 | 'Zdotaccent': [['Z'], ['dotaccent']], 333 | 334 | 'ae': [['a', 'e'], []], 335 | 'oe': [['o', 'e'], []], 336 | 'lslash': [['l'], ['macron']], 337 | 'oslash': [['o'], ['slash']], 338 | 'eth': [['d'], ['macron']], 339 | 'thorn': [['p'], []], 340 | 'germandbls': [['f', 's'], []], 341 | 342 | 'aacute': [['a'], ['acute']], 343 | 'acircumflex': [['a'], ['circumflex']], 344 | 'adieresis': [['a'], ['dieresis']], 345 | 'agrave': [['a'], ['grave']], 346 | 'aring': [['a'], ['ring']], 347 | 'atilde': [['a'], ['tilde']], 348 | 'abreve': [['a'], ['breve']], 349 | 'amacron': [['a'], ['macron']], 350 | 'aogonek': [['a'], ['ogonek']], 351 | 'ccedilla': [['c'], ['cedilla']], 352 | 'cacute': [['c'], ['acute']], 353 | 'ccaron': [['c'], ['caron']], 354 | 'ccircumflex': [['c'], ['circumflex']], 355 | 'cdotaccent': [['c'], ['dotaccent']], 356 | 'dcaron': [['d'], ['caron.alt']], 357 | 'dcroat': [['d'], ['macron']], 358 | 'eacute': [['e'], ['acute']], 359 | 'ecircumflex': [['e'], ['circumflex']], 360 | 'edieresis': [['e'], ['dieresis']], 361 | 'egrave': [['e'], ['grave']], 362 | 'ebreve': [['e'], ['breve']], 363 | 'ecaron': [['e'], ['caron']], 364 | 'edotaccent': [['e'], ['dotaccent']], 365 | 'emacron': [['e'], ['macron']], 366 | 'eogonek': [['e'], ['ogonek']], 367 | 'gbreve': [['g'], ['breve']], 368 | 'gcircumflex': [['g'], ['circumflex']], 369 | 'gcommaaccent': [['g'], ['revcommaaccent']], 370 | 'gdotaccent': [['g'], ['dotaccent']], 371 | 'hbar': [['h'], ['macron']], 372 | 'hcircumflex': [['h'], ['circumflex']], 373 | 'iacute': [['dotlessi'], ['acute']], 374 | 'icircumflex': [['dotlessi'], ['circumflex']], 375 | 'idieresis': [['dotlessi'], ['dieresis']], 376 | 'igrave': [['dotlessi'], ['grave']], 377 | 'ibreve': [['dotlessi'], ['breve']], 378 | 'i.dot': [['i'], []], 379 | 'imacron': [['dotlessi'], ['macron']], 380 | 'iogonek': [['i'], ['ogonek']], 381 | 'itilde': [['dotlessi'], ['tilde']], 382 | 'jcircumflex': [['dotlessj'], ['circumflex']], 383 | 'ij': [['i', 'j'], []], 384 | 'kcommaaccent': [['k'], ['commaaccent']], 385 | 'lacute': [['l'], ['acute']], 386 | 'lcaron': [['l'], ['caron.alt']], 387 | 'lcommaaccent': [['l'], ['commaaccent']], 388 | 'ldot': [['l'], ['periodcentered']], 389 | 'ntilde': [['n'], ['tilde']], 390 | 'nacute': [['n'], ['acute']], 391 | 'ncaron': [['n'], ['caron']], 392 | 'ncommaaccent': [['n'], ['commaaccent']], 393 | 'oacute': [['o'], ['acute']], 394 | 'ocircumflex': [['o'], ['circumflex']], 395 | 'odieresis': [['o'], ['dieresis']], 396 | 'ograve': [['o'], ['grave']], 397 | 'otilde': [['o'], ['tilde']], 398 | 'obreve': [['o'], ['breve']], 399 | 'ohungarumlaut': [['o'], ['hungarumlaut']], 400 | 'omacron': [['o'], ['macron']], 401 | 'racute': [['r'], ['acute']], 402 | 'rcaron': [['r'], ['caron']], 403 | 'rcommaaccent': [['r'], ['commaaccent']], 404 | 'sacute': [['s'], ['acute']], 405 | 'scaron': [['s'], ['caron']], 406 | 'scedilla': [['s'], ['cedilla']], 407 | 'scircumflex': [['s'], ['circumflex']], 408 | 'uni0219': [['s'], ['commaaccent']], 409 | 'tbar': [['t'], ['macron']], 410 | 'tcaron': [['t'], ['caron.alt']], 411 | 'uni0163': [['t'], ['commaaccent']], 412 | 'uni021B': [['t'], ['commaaccent']], 413 | 'uacute': [['u'], ['acute']], 414 | 'ucircumflex': [['u'], ['circumflex']], 415 | 'udieresis': [['u'], ['dieresis']], 416 | 'ugrave': [['u'], ['grave']], 417 | 'ubreve': [['u'], ['breve']], 418 | 'uhungarumlaut': [['u'], ['hungarumlaut']], 419 | 'umacron': [['u'], ['macron']], 420 | 'uogonek': [['u'], ['ogonek']], 421 | 'uring': [['u'], ['ring']], 422 | 'utilde': [['u'], ['tilde']], 423 | 'wacute': [['w'], ['acute']], 424 | 'wcircumflex': [['w'], ['circumflex']], 425 | 'wdieresis': [['w'], ['dieresis']], 426 | 'wgrave': [['w'], ['grave']], 427 | 'yacute': [['y'], ['acute']], 428 | 'ycircumflex': [['y'], ['circumflex']], 429 | 'ydieresis': [['y'], ['dieresis']], 430 | 'ygrave': [['y'], ['grave']], 431 | 'zcaron': [['z'], ['caron']], 432 | 'zacute': [['z'], ['acute']], 433 | 'zdotaccent': [['z'], ['dotaccent']], 434 | } 435 | 436 | 437 | extrasL = { 438 | 'fi': [['f', 'i'], []], 439 | 'fl': [['f', 'l'], []], 440 | 441 | 'f_f': [['f', 'f'], []], 442 | 'f_f_i': [['f', 'f', 'i'], []], 443 | 'f_f_l': [['f', 'f', 'l'], []], 444 | 'f_t': [['f', 't'], []], 445 | 'f_b': [['f', 'b'], []], 446 | 'f_f_b': [['f', 'f', 'b'], []], 447 | 'f_h': [['f', 'h'], []], 448 | 'f_f_h': [['f', 'f', 'h'], []], 449 | 'f_k': [['f', 'k'], []], 450 | 'f_f_k': [['f', 'f', 'k'], []], 451 | 'f_j': [['f', 'j'], []], 452 | 'f_f_j': [['f', 'f', 'j'], []], 453 | 'f_f_t': [['f', 'f', 't'], []], 454 | 'c_t': [['c', 't'], []], 455 | 's_p': [['s', 'p'], []], 456 | 's_t': [['s', 't'], []], 457 | 458 | 459 | 'AE': [['A', 'E'], []], 460 | 'OE': [['O', 'E'], []], 461 | 'Lslash': [['L'], ['macron']], 462 | 'Oslash': [['O'], ['slash']], 463 | 'Eth': [['D'], ['macron']], 464 | 'Thorn': [['P'], []], 465 | 466 | 'Aacute': [['A'], ['acute']], 467 | 'Acircumflex': [['A'], ['circumflex']], 468 | 'Adieresis': [['A'], ['dieresis']], 469 | 'Agrave': [['A'], ['grave']], 470 | 'Aring': [['A'], ['ring']], 471 | 'Atilde': [['A'], ['tilde']], 472 | 'Abreve': [['A'], ['breve']], 473 | 'Amacron': [['A'], ['macron']], 474 | 'Aogonek': [['A'], ['ogonek']], 475 | 'Ccedilla': [['C'], ['cedilla']], 476 | 'Cacute': [['C'], ['acute']], 477 | 'Ccaron': [['C'], ['caron']], 478 | 'Ccircumflex': [['C'], ['circumflex']], 479 | 'Cdotaccent': [['C'], ['dotaccent']], 480 | 'Dcaron': [['D'], ['caron']], 481 | 'Dcroat': [['Eth'], []], 482 | 'Eacute': [['E'], ['acute']], 483 | 'Ecircumflex': [['E'], ['circumflex']], 484 | 'Edieresis': [['E'], ['dieresis']], 485 | 'Egrave': [['E'], ['grave']], 486 | 'Ebreve': [['E'], ['breve']], 487 | 'Ecaron': [['E'], ['caron']], 488 | 'Edotaccent': [['E'], ['dotaccent']], 489 | 'Emacron': [['E'], ['macron']], 490 | 'Eogonek': [['E'], ['ogonek']], 491 | 'Gbreve': [['G'], ['breve']], 492 | 'Gcircumflex': [['G'], ['circumflex']], 493 | 'Gcommaaccent': [['G'], ['commaaccent']], 494 | 'Gdotaccent': [['G'], ['dotaccent']], 495 | 'Hbar': [['H'], ['macron']], 496 | 'Hcircumflex': [['H'], ['circumflex']], 497 | 'Iacute': [['I'], ['acute']], 498 | 'Icircumflex': [['I'], ['circumflex']], 499 | 'Idieresis': [['I'], ['dieresis']], 500 | 'Igrave': [['I'], ['grave']], 501 | 'Ibreve': [['I'], ['breve']], 502 | 'Idotaccent': [['I'], ['dotaccent']], 503 | 'Imacron': [['I'], ['macron']], 504 | 'Iogonek': [['I'], ['ogonek']], 505 | 'Itilde': [['I'], ['tilde']], 506 | 'Jcircumflex': [['J'], ['circumflex']], 507 | 'IJ': [['I', 'J'], []], 508 | 'Kcommaaccent': [['K'], ['commaaccent']], 509 | 'Lacute': [['L'], ['acute']], 510 | 'Lcaron': [['L'], ['caron.alt']], 511 | 'Lcommaaccent': [['L'], ['commaaccent']], 512 | 'Ldot': [['L'], ['periodcentered']], 513 | 'Ntilde': [['N'], ['tilde']], 514 | 'Nacute': [['N'], ['acute']], 515 | 'Ncaron': [['N'], ['caron']], 516 | 'Ncommaaccent': [['N'], ['commaaccent']], 517 | 'Oacute': [['O'], ['acute']], 518 | 'Ocircumflex': [['O'], ['circumflex']], 519 | 'Odieresis': [['O'], ['dieresis']], 520 | 'Ograve': [['O'], ['grave']], 521 | 'Otilde': [['O'], ['tilde']], 522 | 'Obreve': [['O'], ['breve']], 523 | 'Ohungarumlaut': [['O'], ['hungarumlaut']], 524 | 'Omacron': [['O'], ['macron']], 525 | 'Racute': [['R'], ['acute']], 526 | 'Rcaron': [['R'], ['caron']], 527 | 'Rcommaaccent': [['R'], ['commaaccent']], 528 | 'Sacute': [['S'], ['acute']], 529 | 'Scaron': [['S'], ['caron']], 530 | 'Scedilla': [['S'], ['cedilla']], 531 | 'Scircumflex': [['S'], ['circumflex']], 532 | 'uni0218': [['S'], ['commaaccent']], 533 | 'Tbar': [['T'], ['macron']], 534 | 'Tcaron': [['T'], ['caron']], 535 | 'uni0162': [['T'], ['commaaccent']], 536 | 'uni021A': [['T'], ['commaaccent']], 537 | 'Uacute': [['U'], ['acute']], 538 | 'Ucircumflex': [['U'], ['circumflex']], 539 | 'Udieresis': [['U'], ['dieresis']], 540 | 'Ugrave': [['U'], ['grave']], 541 | 'Ubreve': [['U'], ['breve']], 542 | 'Uhungarumlaut': [['U'], ['hungarumlaut']], 543 | 'Umacron': [['U'], ['macron']], 544 | 'Uogonek': [['U'], ['ogonek']], 545 | 'Uring': [['U'], ['ring']], 546 | 'Utilde': [['U'], ['tilde']], 547 | 'Wacute': [['W'], ['acute']], 548 | 'Wcircumflex': [['W'], ['circumflex']], 549 | 'Wdieresis': [['W'], ['dieresis']], 550 | 'Wgrave': [['W'], ['grave']], 551 | 'Yacute': [['Y'], ['acute']], 552 | 'Ycircumflex': [['Y'], ['circumflex']], 553 | 'Ydieresis': [['Y'], ['dieresis']], 554 | 'Ygrave': [['Y'], ['grave']], 555 | 'Zcaron': [['Z'], ['caron']], 556 | 'Zacute': [['Z'], ['acute']], 557 | 'Zdotaccent': [['Z'], ['dotaccent']], 558 | 559 | 'ae': [['a', 'e'], []], 560 | 'oe': [['o', 'e'], []], 561 | 'lslash': [['l'], ['macron']], 562 | 'oslash': [['o'], ['slash']], 563 | 'eth': [['d'], ['macron']], 564 | 'thorn': [['p'], []], 565 | 'germandbls': [['f', 's'], []], 566 | 567 | 'aacute': [['a'], ['acute']], 568 | 'acircumflex': [['a'], ['circumflex']], 569 | 'adieresis': [['a'], ['dieresis']], 570 | 'agrave': [['a'], ['grave']], 571 | 'aring': [['a'], ['ring']], 572 | 'atilde': [['a'], ['tilde']], 573 | 'abreve': [['a'], ['breve']], 574 | 'amacron': [['a'], ['macron']], 575 | 'aogonek': [['a'], ['ogonek']], 576 | 'ccedilla': [['c'], ['cedilla']], 577 | 'cacute': [['c'], ['acute']], 578 | 'ccaron': [['c'], ['caron']], 579 | 'ccircumflex': [['c'], ['circumflex']], 580 | 'cdotaccent': [['c'], ['dotaccent']], 581 | 'dcaron': [['d'], ['caron.alt']], 582 | 'dcroat': [['d'], ['macron']], 583 | 'eacute': [['e'], ['acute']], 584 | 'ecircumflex': [['e'], ['circumflex']], 585 | 'edieresis': [['e'], ['dieresis']], 586 | 'egrave': [['e'], ['grave']], 587 | 'ebreve': [['e'], ['breve']], 588 | 'ecaron': [['e'], ['caron']], 589 | 'edotaccent': [['e'], ['dotaccent']], 590 | 'emacron': [['e'], ['macron']], 591 | 'eogonek': [['e'], ['ogonek']], 592 | 'gbreve': [['g'], ['breve']], 593 | 'gcircumflex': [['g'], ['circumflex']], 594 | 'gcommaaccent': [['g'], ['revcommaaccent']], 595 | 'gdotaccent': [['g'], ['dotaccent']], 596 | 'hbar': [['h'], ['macron']], 597 | 'hcircumflex': [['h'], ['circumflex']], 598 | 'iacute': [['dotlessi'], ['acute']], 599 | 'icircumflex': [['dotlessi'], ['circumflex']], 600 | 'idieresis': [['dotlessi'], ['dieresis']], 601 | 'igrave': [['dotlessi'], ['grave']], 602 | 'ibreve': [['dotlessi'], ['breve']], 603 | 'i.dot': [['i'], []], 604 | 'imacron': [['dotlessi'], ['macron']], 605 | 'iogonek': [['i'], ['ogonek']], 606 | 'itilde': [['dotlessi'], ['tilde']], 607 | 'jcircumflex': [['dotlessj'], ['circumflex']], 608 | 'ij': [['i', 'j'], []], 609 | 'kcommaaccent': [['k'], ['commaaccent']], 610 | 'lacute': [['l'], ['acute']], 611 | 'lcaron': [['l'], ['caron.alt']], 612 | 'lcommaaccent': [['l'], ['commaaccent']], 613 | 'ldot': [['l'], ['periodcentered']], 614 | 'ntilde': [['n'], ['tilde']], 615 | 'nacute': [['n'], ['acute']], 616 | 'ncaron': [['n'], ['caron']], 617 | 'ncommaaccent': [['n'], ['commaaccent']], 618 | 'oacute': [['o'], ['acute']], 619 | 'ocircumflex': [['o'], ['circumflex']], 620 | 'odieresis': [['o'], ['dieresis']], 621 | 'ograve': [['o'], ['grave']], 622 | 'otilde': [['o'], ['tilde']], 623 | 'obreve': [['o'], ['breve']], 624 | 'ohungarumlaut': [['o'], ['hungarumlaut']], 625 | 'omacron': [['o'], ['macron']], 626 | 'racute': [['r'], ['acute']], 627 | 'rcaron': [['r'], ['caron']], 628 | 'rcommaaccent': [['r'], ['commaaccent']], 629 | 'sacute': [['s'], ['acute']], 630 | 'scaron': [['s'], ['caron']], 631 | 'scedilla': [['s'], ['cedilla']], 632 | 'scircumflex': [['s'], ['circumflex']], 633 | 'uni0219': [['s'], ['commaaccent']], 634 | 'tbar': [['t'], ['macron']], 635 | 'tcaron': [['t'], ['caron.alt']], 636 | 'uni0163': [['t'], ['commaaccent']], 637 | 'uni021B': [['t'], ['commaaccent']], 638 | 'uacute': [['u'], ['acute']], 639 | 'ucircumflex': [['u'], ['circumflex']], 640 | 'udieresis': [['u'], ['dieresis']], 641 | 'ugrave': [['u'], ['grave']], 642 | 'ubreve': [['u'], ['breve']], 643 | 'uhungarumlaut': [['u'], ['hungarumlaut']], 644 | 'umacron': [['u'], ['macron']], 645 | 'uogonek': [['u'], ['ogonek']], 646 | 'uring': [['u'], ['ring']], 647 | 'utilde': [['u'], ['tilde']], 648 | 'wacute': [['w'], ['acute']], 649 | 'wcircumflex': [['w'], ['circumflex']], 650 | 'wdieresis': [['w'], ['dieresis']], 651 | 'wgrave': [['w'], ['grave']], 652 | 'yacute': [['y'], ['acute']], 653 | 'ycircumflex': [['y'], ['circumflex']], 654 | 'ydieresis': [['y'], ['dieresis']], 655 | 'ygrave': [['y'], ['grave']], 656 | 'zcaron': [['z'], ['caron']], 657 | 'zacute': [['z'], ['acute']], 658 | 'zdotaccent': [['z'], ['dotaccent']], 659 | 660 | 'ae.sc': [['a.sc', 'e.sc'], []], 661 | 'oe.sc': [['o.sc', 'e.sc'], []], 662 | 'lslash.sc': [['l.sc'], ['macron']], 663 | 'oslash.sc': [['o.sc'], ['slash']], 664 | 'eth.sc': [['d.sc'], ['macron']], 665 | 'thorn.sc': [['p.sc'], []], 666 | 'germandbls.sc': [['s.sc', 's.sc'], []], 667 | 'dotlessi.sc': [['i.sc'], []], 668 | 'dotlessj.sc': [['j.sc'], []], 669 | 670 | 'aacute.sc': [['a.sc'], ['acute']], 671 | 'acircumflex.sc': [['a.sc'], ['circumflex']], 672 | 'adieresis.sc': [['a.sc'], ['dieresis']], 673 | 'agrave.sc': [['a.sc'], ['grave']], 674 | 'aring.sc': [['a.sc'], ['ring']], 675 | 'atilde.sc': [['a.sc'], ['tilde']], 676 | 'abreve.sc': [['a.sc'], ['breve']], 677 | 'amacron.sc': [['a.sc'], ['macron']], 678 | 'aogonek.sc': [['a.sc'], ['ogonek']], 679 | 'ccedilla.sc': [['c.sc'], ['cedilla']], 680 | 'cacute.sc': [['c.sc'], ['acute']], 681 | 'ccaron.sc': [['c.sc'], ['caron']], 682 | 'ccircumflex.sc': [['c.sc'], ['circumflex']], 683 | 'cdotaccent.sc': [['c.sc'], ['dotaccent']], 684 | 'dcaron.sc': [['d.sc'], ['caron']], 685 | 'dcroat.sc': [['eth.sc'], []], 686 | 'eacute.sc': [['e.sc'], ['acute']], 687 | 'ecircumflex.sc': [['e.sc'], ['circumflex']], 688 | 'edieresis.sc': [['e.sc'], ['dieresis']], 689 | 'egrave.sc': [['e.sc'], ['grave']], 690 | 'ebreve.sc': [['e.sc'], ['breve']], 691 | 'ecaron.sc': [['e.sc'], ['caron']], 692 | 'edotaccent.sc': [['e.sc'], ['dotaccent']], 693 | 'emacron.sc': [['e.sc'], ['macron']], 694 | 'eogonek.sc': [['e.sc'], ['ogonek']], 695 | 'gbreve.sc': [['g.sc'], ['breve']], 696 | 'gcircumflex.sc': [['g.sc'], ['circumflex']], 697 | 'gcommaaccent.sc': [['g.sc'], ['commaaccent']], 698 | 'gdotaccent.sc': [['g.sc'], ['dotaccent']], 699 | 'hbar.sc': [['h.sc'], ['macron']], 700 | 'hcircumflex.sc': [['h.sc'], ['circumflex']], 701 | 'iacute.sc': [['i.sc'], ['acute']], 702 | 'icircumflex.sc': [['i.sc'], ['circumflex']], 703 | 'idieresis.sc': [['i.sc'], ['dieresis']], 704 | 'igrave.sc': [['i.sc'], ['grave']], 705 | 'ibreve.sc': [['i.sc'], ['breve']], 706 | 'i.dot.sc': [['i.sc'], ['dotaccent']], 707 | 'imacron.sc': [['i.sc'], ['macron']], 708 | 'iogonek.sc': [['i.sc'], ['ogonek']], 709 | 'itilde.sc': [['i.sc'], ['tilde']], 710 | 'jcircumflex.sc': [['j.sc'], ['circumflex']], 711 | 'ij.sc': [['i.sc', 'j.sc'], []], 712 | 'kcommaaccent.sc': [['k.sc'], ['commaaccent']], 713 | 'lacute.sc': [['l.sc'], ['acute']], 714 | 'lcaron.sc': [['l.sc'], ['caron.alt']], 715 | 'lcommaaccent.sc': [['l.sc'], ['commaaccent']], 716 | 'ldot.sc': [['l.sc'], ['periodcentered']], 717 | 'ntilde.sc': [['n.sc'], ['tilde']], 718 | 'nacute.sc': [['n.sc'], ['acute']], 719 | 'ncaron.sc': [['n.sc'], ['caron']], 720 | 'ncommaaccent.sc': [['n.sc'], ['commaaccent']], 721 | 'oacute.sc': [['o.sc'], ['acute']], 722 | 'ocircumflex.sc': [['o.sc'], ['circumflex']], 723 | 'odieresis.sc': [['o.sc'], ['dieresis']], 724 | 'ograve.sc': [['o.sc'], ['grave']], 725 | 'otilde.sc': [['o.sc'], ['tilde']], 726 | 'obreve.sc': [['o.sc'], ['breve']], 727 | 'ohungarumlaut.sc': [['o.sc'], ['hungarumlaut']], 728 | 'omacron.sc': [['o.sc'], ['macron']], 729 | 'racute.sc': [['r.sc'], ['acute']], 730 | 'rcaron.sc': [['r.sc'], ['caron']], 731 | 'rcommaaccent.sc': [['r.sc'], ['commaaccent']], 732 | 'sacute.sc': [['s.sc'], ['acute']], 733 | 'scaron.sc': [['s.sc'], ['caron']], 734 | 'scedilla.sc': [['s.sc'], ['cedilla']], 735 | 'scircumflex.sc': [['s.sc'], ['circumflex']], 736 | 'uni0219.sc': [['s.sc'], ['commaaccent']], 737 | 'tbar.sc': [['t.sc'], ['macron']], 738 | 'tcaron.sc': [['t.sc'], ['caron']], 739 | 'uni0163.sc': [['t.sc'], ['commaaccent']], 740 | 'uni021B.sc': [['t.sc'], ['commaaccent']], 741 | 'uacute.sc': [['u.sc'], ['acute']], 742 | 'ucircumflex.sc': [['u.sc'], ['circumflex']], 743 | 'udieresis.sc': [['u.sc'], ['dieresis']], 744 | 'ugrave.sc': [['u.sc'], ['grave']], 745 | 'ubreve.sc': [['u.sc'], ['breve']], 746 | 'uhungarumlaut.sc': [['u.sc'], ['hungarumlaut']], 747 | 'umacron.sc': [['u.sc'], ['macron']], 748 | 'uogonek.sc': [['u.sc'], ['ogonek']], 749 | 'uring.sc': [['u.sc'], ['ring']], 750 | 'utilde.sc': [['u.sc'], ['tilde']], 751 | 'wacute.sc': [['w.sc'], ['acute']], 752 | 'wcircumflex.sc': [['w.sc'], ['circumflex']], 753 | 'wdieresis.sc': [['w.sc'], ['dieresis']], 754 | 'wgrave.sc': [['w.sc'], ['grave']], 755 | 'yacute.sc': [['y.sc'], ['acute']], 756 | 'ycircumflex.sc': [['y.sc'], ['circumflex']], 757 | 'ydieresis.sc': [['y.sc'], ['dieresis']], 758 | 'ygrave.sc': [['y.sc'], ['grave']], 759 | 'zcaron.sc': [['z.sc'], ['caron']], 760 | 'zacute.sc': [['z.sc'], ['acute']], 761 | 'zdotaccent.sc': [['z.sc'], ['dotaccent']] 762 | } 763 | 764 | class Process(BaseWindowController): 765 | 766 | def __init__(self): 767 | self.w = FloatingWindow((310, 170)) 768 | self.w.textBox = TextBox((10, 10, -10, 16), "Diacritics & Ligatures", sizeStyle = "regular", alignment = "center") 769 | self.w.textBoxEncodingS = CheckBox((10, 40, -10, 20), "Encoding S", sizeStyle = "small", 770 | callback=self.textBoxEncodingSCallback, value = False) 771 | self.w.textBoxEncodingM = CheckBox((10, 70, -10, 20), "Encoding M", sizeStyle = "small", 772 | callback=self.textBoxEncodingMCallback, value = False) 773 | self.w.textBoxEncodingL = CheckBox((10, 100, -10, 20), "Encoding L", sizeStyle = "small", 774 | callback=self.textBoxEncodingLCallback, value = False) 775 | self.w.buttonMake = Button((10, -20, 90, 15), "Make", sizeStyle = "small", callback=self.showProgress) 776 | self.w.buttonDelete = Button((110, -20, 90, 15), "Delete All", sizeStyle = "small", callback=self.showDelete) 777 | self.w.buttonClose = Button((210, -20, 90, 15), "Close", sizeStyle = "small", callback=self.closeWindow) 778 | self.w.center() 779 | self.w.open() 780 | 781 | def closeWindow(self, sender): 782 | self.w.close() 783 | 784 | def textBoxEncodingSCallback(self, sender): 785 | if sender.get(): 786 | self.w.textBoxEncodingM.set(False) 787 | self.w.textBoxEncodingL.set(False) 788 | 789 | def textBoxEncodingMCallback(self, sender): 790 | if sender.get(): 791 | self.w.textBoxEncodingS.set(False) 792 | self.w.textBoxEncodingL.set(False) 793 | 794 | def textBoxEncodingLCallback(self, sender): 795 | if sender.get(): 796 | self.w.textBoxEncodingS.set(False) 797 | self.w.textBoxEncodingM.set(False) 798 | 799 | def showProgress(self, sender): 800 | if self.w.textBoxEncodingL.get(): 801 | self.progress = self.startProgress("Checking UFO...", tickCount=100) 802 | glyphsToMake = self.defineGlyphsToMake(f, extrasL) 803 | self.progress.close() 804 | self.progress = self.startProgress("Processing L...", tickCount=100) 805 | self.makeGlyphs(f, glyphsToMake) 806 | self.progress.close() 807 | elif self.w.textBoxEncodingM.get(): 808 | self.progress = self.startProgress("Checking UFO...", tickCount=100) 809 | glyphsToMake = self.defineGlyphsToMake(f, extrasM) 810 | self.progress.close() 811 | self.progress = self.startProgress("Processing M...", tickCount=100) 812 | self.makeGlyphs(f, glyphsToMake) 813 | self.progress.close() 814 | elif self.w.textBoxEncodingS.get(): 815 | self.progress = self.startProgress("Checking UFO...", tickCount=100) 816 | glyphsToMake = self.defineGlyphsToMake(f, extrasS) 817 | self.progress.close() 818 | self.progress = self.startProgress("Processing S...", tickCount=100) 819 | self.makeGlyphs(f, glyphsToMake) 820 | self.progress.close() 821 | self.w.close() 822 | 823 | def showDelete(self, sender): 824 | self.progress = self.startProgress("Deleting Diactitics...", tickCount=100) 825 | self.deleteAll(f) 826 | self.progress.close() 827 | 828 | def deleteAll(self, f): 829 | self.progress.setTickCount(len(extrasL.keys())) 830 | for i in extrasL.keys(): 831 | self.progress.update() 832 | if i in f.keys(): 833 | f.removeGlyph(i) 834 | 835 | def defineGlyphsToMake(self, f, extrasDict): 836 | glyphsToMake = {} 837 | self.progress.setTickCount(len(extrasDict.keys())) 838 | for i in extrasDict.keys(): 839 | self.progress.update() 840 | newGlyphName = i 841 | basesNames = extrasDict[i][0] 842 | accentsNames = extrasDict[i][1] 843 | missing = False 844 | #print newGlyphName, basesNames, accentsNames 845 | if i in f.keys(): 846 | continue 847 | #print 'glyph ' + i + ' already exists' 848 | else: 849 | #check if components are present in the font 850 | for base in basesNames: 851 | if len(accentsNames) > 0: 852 | for accent in accentsNames: 853 | if base in f.keys() and accent in f.keys(): 854 | continue 855 | elif base not in f.keys(): 856 | #print 'glyph ' + base + ' is missing' 857 | #missingBases.append(base) 858 | missing = True 859 | elif accent not in f.keys(): 860 | #print 'glyph ' + accent + ' is missing' 861 | #missingAccents.append(accent) 862 | missing = True 863 | else: 864 | if base not in f.keys(): 865 | #print 'glyph ' + base + ' is missing' 866 | missing = True 867 | if missing == False: 868 | #print 'glyph ' + i + ' to create' 869 | glyphsToMake[i] = (basesNames , accentsNames) 870 | 871 | return glyphsToMake 872 | 873 | def makeGlyphs(self, f, glyphsToMake): 874 | self.progress.setTickCount(len(glyphsToMake.keys())) 875 | for i in glyphsToMake.keys(): 876 | self.progress.update() 877 | basesNames = glyphsToMake[i][0] 878 | accentsNames = glyphsToMake[i][1] 879 | f.newGlyph(i) 880 | f[i].width = 0 881 | yShift = 0 882 | xShift = 0 883 | markColor = (0, 1, 1, 0.5) 884 | for base in basesNames: 885 | if base.isupper(): 886 | yShift = yShiftCaps 887 | xShift = xShiftCaps 888 | if base[-2:] == 'sc': 889 | yShift = yShiftSmallCaps 890 | xShift = xShiftSmallCaps 891 | f[i].appendComponent(base, (f[i].width, 0)) 892 | f[i].width += f[base].width 893 | for accent in accentsNames: 894 | if accent == 'ogonek' or accent == 'cedilla' or accent == 'slash' or accent == 'commaaccent' or accent == 'caron.alt' or accent == 'periodcentered': 895 | yShift = 0 896 | f[i].appendComponent(accent, ((f[i].width/2 - f[accent].width/2)+xShift, yShift)) 897 | if i in toBeDecomposed: 898 | markColor = (0, 1, 0, 0.5) 899 | for j in f[i].components: 900 | j.decompose() 901 | elif i in metricsAdjust: 902 | markColor = (0, 0, 1, 0.5) 903 | f[i].mark = markColor 904 | f[i].update() 905 | 906 | def getItalAngle(f): 907 | italAngle = f.info.italicAngle 908 | if italAngle == None: 909 | italAngle = 0 910 | return italAngle 911 | 912 | def getItalRatio(italAngle): 913 | italRatio = math.tan(math.radians(-italAngle)) 914 | return italRatio 915 | 916 | def getxShift(yShift, italRatio): 917 | xShift = int(yShift * italRatio) 918 | return xShift 919 | 920 | 921 | f = CurrentFont() 922 | glyphsToMake = {} 923 | missingBases = [] 924 | missingAccents = [] 925 | 926 | if 'O' in f.keys() and 'o' in f.keys(): 927 | yShiftCaps = f['O'].box[3] - f['o'].box[3] 928 | else: 929 | yShiftCaps = 0 930 | if 'o' in f.keys() and 'o.sc' in f.keys(): 931 | yShiftSmallCaps = f['o.sc'].box[3] - f['o'].box[3] 932 | else: 933 | yShiftSmallCaps = 0 934 | italAngle = getItalAngle(f) 935 | italRatio = getItalRatio(italAngle) 936 | xShiftCaps = getxShift(yShiftCaps, italRatio) 937 | xShiftSmallCaps = getxShift(yShiftSmallCaps, italRatio) 938 | 939 | Process() 940 | f.update() 941 | -------------------------------------------------------------------------------- /MakeFractions/MakeFractions.py: -------------------------------------------------------------------------------- 1 | from vanilla import * 2 | from defconAppKit.windows.baseWindow import BaseWindowController 3 | import math 4 | 5 | inferiors = { 6 | 'zeroinferior': ['zerosuperior'], 7 | 'oneinferior': ['onesuperior'], 8 | 'twoinferior': ['twosuperior'], 9 | 'threeinferior': ['threesuperior'], 10 | 'fourinferior': ['foursuperior'], 11 | 'fiveinferior': ['fivesuperior'], 12 | 'sixinferior': ['sixsuperior'], 13 | 'seveninferior': ['sevensuperior'], 14 | 'eightinferior': ['eightsuperior'], 15 | 'nineinferior': ['ninesuperior'] 16 | } 17 | 18 | numerators = { 19 | 'zero.numerator': ['zerosuperior'], 20 | 'one.numerator': ['onesuperior'], 21 | 'two.numerator': ['twosuperior'], 22 | 'three.numerator': ['threesuperior'], 23 | 'four.numerator': ['foursuperior'], 24 | 'five.numerator': ['fivesuperior'], 25 | 'six.numerator': ['sixsuperior'], 26 | 'seven.numerator': ['sevensuperior'], 27 | 'eight.numerator': ['eightsuperior'], 28 | 'nine.numerator': ['ninesuperior'] 29 | } 30 | 31 | denominators = { 32 | 'zero.denominator': ['zerosuperior'], 33 | 'one.denominator': ['onesuperior'], 34 | 'two.denominator': ['twosuperior'], 35 | 'three.denominator': ['threesuperior'], 36 | 'four.denominator': ['foursuperior'], 37 | 'five.denominator': ['fivesuperior'], 38 | 'six.denominator': ['sixsuperior'], 39 | 'seven.denominator': ['sevensuperior'], 40 | 'eight.denominator': ['eightsuperior'], 41 | 'nine.denominator': ['ninesuperior'] 42 | } 43 | 44 | fractionsML = { 45 | 'onehalf': ['onesuperior', 'fraction', 'twosuperior'], 46 | 'onequarter': ['onesuperior', 'fraction', 'foursuperior'], 47 | 'threequarters': ['threesuperior', 'fraction', 'foursuperior'], 48 | 'onethird': ['onesuperior', 'fraction', 'threesuperior'], 49 | 'twothirds': ['twosuperior', 'fraction', 'threesuperior'], 50 | 'oneeighth': ['onesuperior', 'fraction', 'eightsuperior'], 51 | 'threeeighths': ['threesuperior', 'fraction', 'eightsuperior'], 52 | 'fiveeighths': ['fivesuperior', 'fraction', 'eightsuperior'], 53 | 'seveneighths': ['sevensuperior', 'fraction', 'eightsuperior'], 54 | 'onefifth': ['onesuperior', 'fraction', 'fivesuperior'], 55 | 'twofifths': ['twosuperior', 'fraction', 'fivesuperior'], 56 | 'threefifths': ['threesuperior', 'fraction', 'fivesuperior'], 57 | 'fourfifths': ['foursuperior', 'fraction', 'fivesuperior'], 58 | 'onesixth': ['onesuperior', 'fraction', 'sixsuperior'], 59 | 'fivesixths': ['fivesuperior', 'fraction', 'sixsuperior'], 60 | 'oneseventh': ['onesuperior', 'fraction', 'sevensuperior'], 61 | 'twosevenths': ['twosuperior', 'fraction', 'sevensuperior'], 62 | 'threesevenths': ['threesuperior', 'fraction', 'sevensuperior'], 63 | 'foursevenths': ['foursuperior', 'fraction', 'sevensuperior'], 64 | 'fivesevenths': ['fivesuperior', 'fraction', 'sevensuperior'], 65 | 'sixsevenths': ['sixsuperior', 'fraction', 'sevensuperior'], 66 | 'oneninth': ['onesuperior', 'fraction', 'ninesuperior'], 67 | 'twoninths': ['twosuperior', 'fraction', 'ninesuperior'], 68 | 'fourninths': ['foursuperior', 'fraction', 'ninesuperior'], 69 | 'fiveninths': ['fivesuperior', 'fraction', 'ninesuperior'], 70 | 'sevenninths': ['sevensuperior', 'fraction', 'ninesuperior'], 71 | 'eightninths': ['eightsuperior', 'fraction', 'ninesuperior'] 72 | } 73 | 74 | fractionsS = { 75 | 'onehalf': ['onesuperior', 'fraction', 'twosuperior'], 76 | 'onequarter': ['onesuperior', 'fraction', 'foursuperior'], 77 | 'threequarters': ['threesuperior', 'fraction', 'foursuperior'], 78 | } 79 | 80 | class Process(BaseWindowController): 81 | 82 | def __init__(self): 83 | self.w = FloatingWindow((310, 150)) 84 | 85 | self.w.textBox = TextBox((10, 10, -10, 16), "Fractions & Ordinals", sizeStyle = "regular", alignment = "center") 86 | self.w.textBoxEncodingS = CheckBox((10, 40, -10, 20), "Encoding S", sizeStyle = "small", 87 | callback=self.textBoxEncodingSCallback, value = False) 88 | self.w.textBoxEncodingML = CheckBox((10, 70, -10, 20), "Encoding M & L", sizeStyle = "small", 89 | callback=self.textBoxEncodingMLCallback, value = False) 90 | 91 | self.w.buttonMake = Button((10, -20, 90, 15), "Make", sizeStyle = "small", callback=self.showProgress) 92 | self.w.buttonDelete = Button((110, -20, 90, 15), "Delete All", sizeStyle = "small", callback=self.showDelete) 93 | self.w.buttonClose = Button((210, -20, 90, 15), "Close", sizeStyle = "small", callback=self.closeWindow) 94 | 95 | self.w.center() 96 | self.w.open() 97 | 98 | def closeWindow(self, sender): 99 | self.w.close() 100 | 101 | def textBoxEncodingSCallback(self, sender): 102 | if sender.get(): 103 | self.w.textBoxEncodingML.set(False) 104 | 105 | def textBoxEncodingMLCallback(self, sender): 106 | if sender.get(): 107 | self.w.textBoxEncodingS.set(False) 108 | 109 | def showProgress(self, sender): 110 | if self.w.textBoxEncodingML.get(): 111 | self.progress = self.startProgress("Checking UFO...", tickCount=100) 112 | fractionsToMake = self.defineGlyphsToMake(f, fractionsML) 113 | self.progress.close() 114 | self.progress = self.startProgress("Making Fractions M & L...", tickCount=100) 115 | self.makeFractions(fractionsToMake) 116 | self.progress.close() 117 | 118 | self.progress = self.startProgress("Checking UFO...", tickCount=100) 119 | inferiorsToMake = self.defineGlyphsToMake(f, inferiors) 120 | self.progress.close() 121 | self.progress = self.startProgress("Making Inferiors...", tickCount=100) 122 | self.makeInferiors(inferiorsToMake) 123 | self.progress.close() 124 | 125 | self.progress = self.startProgress("Checking UFO...", tickCount=100) 126 | numeratorsToMake = self.defineGlyphsToMake(f, numerators) 127 | self.progress.close() 128 | self.progress = self.startProgress("Making Numerators...", tickCount=100) 129 | self.makeNumerators(numeratorsToMake) 130 | self.progress.close() 131 | 132 | self.progress = self.startProgress("Checking UFO...", tickCount=100) 133 | denominatorsToMake = self.defineGlyphsToMake(f, denominators) 134 | self.progress.close() 135 | self.progress = self.startProgress("Making Denominators...", tickCount=100) 136 | self.makeDenominators(denominatorsToMake) 137 | self.progress.close() 138 | 139 | elif self.w.textBoxEncodingS.get: 140 | self.progress = self.startProgress("Checking UFO...", tickCount=100) 141 | fractionsToMake = self.defineGlyphsToMake(f, fractionsS) 142 | self.progress.close() 143 | self.progress = self.startProgress("Making Fractions S...", tickCount=100) 144 | self.makeFractions(fractionsToMake) 145 | self.progress.close() 146 | 147 | self.w.close() 148 | 149 | def showDelete(self, sender): 150 | self.progress = self.startProgress("Deleting...", tickCount=100) 151 | self.deleteAll(f) 152 | self.progress.close() 153 | 154 | def deleteAll(self, f): 155 | self.progress.setTickCount(len(fractionsML.keys()) + len(inferiors.keys()) + len(numerators.keys()) + len(denominators.keys())) 156 | for i in fractionsML.keys(): 157 | self.progress.update() 158 | if i in f.keys(): 159 | f.removeGlyph(i) 160 | for i in inferiors.keys(): 161 | self.progress.update() 162 | if i in f.keys(): 163 | f.removeGlyph(i) 164 | for i in numerators.keys(): 165 | self.progress.update() 166 | if i in f.keys(): 167 | f.removeGlyph(i) 168 | for i in denominators.keys(): 169 | self.progress.update() 170 | if i in f.keys(): 171 | f.removeGlyph(i) 172 | 173 | def defineGlyphsToMake(self, f, glyphsDict): 174 | glyphsToMake = {} 175 | self.progress.setTickCount(len(glyphsDict.keys())) 176 | for i in glyphsDict.keys(): 177 | self.progress.update() 178 | newGlyphName = i 179 | if i in f.keys(): 180 | #print 'glyph ' + i + ' already exists' 181 | continue 182 | else: 183 | componentsList = [] 184 | for j in glyphsDict[i]: 185 | missing = False 186 | if j in f.keys(): 187 | #print 'glyph ' + j + ' in the font' 188 | componentsList.append(j) 189 | continue 190 | else: 191 | missing = True 192 | if missing == False: 193 | glyphsToMake[i] = componentsList 194 | 195 | return glyphsToMake 196 | 197 | def makeFractions(self, fractionsDict): 198 | self.progress.setTickCount(len(fractionsDict.keys())) 199 | for i in fractionsDict.keys(): 200 | self.progress.update() 201 | f.newGlyph(i) 202 | f[i].mark = (1, 0, 1, 0.5) 203 | firstSup = fractionsDict[i][0] 204 | fraction = fractionsDict[i][1] 205 | secondInf = fractionsDict[i][2] 206 | f[i].width = f[firstSup].width + f[fraction].width + f[secondInf].width 207 | f[i].appendComponent(firstSup, (0, 0)) 208 | f[i].appendComponent(fraction, (f[firstSup].width, 0)) 209 | f[i].appendComponent(secondInf, (f[firstSup].width + f[fraction].width + xShiftInferiors, yShiftInferiors)) 210 | 211 | def makeInferiors(self, inferiorsDict): 212 | self.progress.setTickCount(len(inferiorsDict.keys())) 213 | for i in inferiorsDict.keys(): 214 | self.progress.update() 215 | f.newGlyph(i) 216 | f[i].mark = (1, 0, 0, 0.5) 217 | component = inferiorsDict[i][0] 218 | f[i].width = f[component].width 219 | f[i].appendComponent(component, (xShiftInferiors, yShiftInferiors)) 220 | 221 | def makeNumerators(self, numeratorsDict): 222 | self.progress.setTickCount(len(numeratorsDict.keys())) 223 | for i in numeratorsDict.keys(): 224 | self.progress.update() 225 | f.newGlyph(i) 226 | f[i].mark = (1, 0, 0, 0.5) 227 | component = numeratorsDict[i][0] 228 | f[i].width = f[component].width 229 | f[i].appendComponent(component, (xShiftNumerators, yShiftNumerators)) 230 | 231 | def makeDenominators(self, denominatorsDict): 232 | self.progress.setTickCount(len(denominatorsDict.keys())) 233 | for i in denominatorsDict.keys(): 234 | self.progress.update() 235 | f.newGlyph(i) 236 | f[i].mark = (1, 0, 0, 0.5) 237 | component = denominatorsDict[i][0] 238 | f[i].width = f[component].width 239 | f[i].appendComponent(component, (xShiftDenominators, yShiftDenominators)) 240 | 241 | def getItalAngle(f): 242 | italAngle = f.info.italicAngle 243 | if italAngle == None: 244 | italAngle = 0 245 | return italAngle 246 | 247 | def getItalRatio(italAngle): 248 | italRatio = math.tan(math.radians(-italAngle)) 249 | return italRatio 250 | 251 | def getxShift(yShift, italRatio): 252 | xShift = int(yShift * italRatio) 253 | return xShift 254 | 255 | 256 | 257 | f = CurrentFont() 258 | italAngle = getItalAngle(f) 259 | italRatio = getItalRatio(italAngle) 260 | 261 | zeroSupHeight = f['zerosuperior'].box[3] - f['zerosuperior'].box[1] 262 | 263 | yShiftInferiors = - f['onesuperior'].box[1] 264 | xShiftInferiors = getxShift(yShiftInferiors, italRatio) 265 | 266 | yShiftNumerators = zeroSupHeight * 30/100 267 | xShiftNumerators = getxShift(yShiftNumerators, italRatio) 268 | 269 | yShiftDenominators = - f['onesuperior'].box[1] - zeroSupHeight * 30/100 270 | xShiftDenominators = getxShift(yShiftDenominators, italRatio) 271 | 272 | Process() 273 | f.update() 274 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RobofontTools 2 | ============= 3 | 4 | Tools for working in RoboFont 5 | 6 | - Properties: Extension that displays in the Glyph window. It shows selected bcp distances (x, y), the selection distances (x, y), the number of contours, the number of IN points, the number of OFF points. 7 | 8 | - StemsAnalyser: Extension setting PostScriptStemSnapH and PostScriptStemSnapV according to automatic 9 | glyphs measurements. May be useful to define a CVT Table as well. 10 | 11 | - ConvertSegments: Scripts to convert selected lines to curves, and selected curves to lines. 12 | 13 | - AssignFontLayer: Script window to copy all glyphs from a font to another font's new custom layer. 14 | 15 | - Interpolate: Script window to interpolate between two masters. Useful to generate Weight and Width instances, and SmallCapitals, and more. 16 | 17 | - CopyToMask: Script that copies foreground current glyph to Mask layer. 18 | 19 | - MakeAccents: Script preparing diacritics and ligature, FY encodings. 20 | 21 | - MakeFractions: Script making fractions, inferiors, numerators and denominators out of superior figures, FY encodings. 22 | 23 | - CreateEncoding: Script setting font GlyphOrder for FY encoding S M L. 24 | 25 | - CheckGlyphIntegrity: Script checking for glyphs with: mixed contours and components, overlapping components, overlapping contours. Highlight them and prints a report. 26 | 27 | - ExpandKerning: Expand group (class) kerning to flat kerning, delete groups. 28 | 29 | - GenerateFont: Generate font window, add the possibility to export kern table. 30 | 31 | - ConvertToQuadratic: Generates a new UFO with Quadratic (TrueType) curves. 32 | -------------------------------------------------------------------------------- /StemsAnalyser/StemsAnalyser.roboFontExt/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | addToMenu 6 | 7 | 8 | path 9 | StemsAnalyser.py 10 | preferredName 11 | StemsAnalyser 12 | shortKey 13 | 14 | 15 | 16 | developer 17 | Jeremie Hornus 18 | developerURL 19 | 20 | html 21 | 22 | launchAtStartUp 23 | 0 24 | mainScript 25 | 26 | name 27 | StemsAnalyser 28 | timeStamp 29 | 1421143668.8228281 30 | version 31 | 1.0 32 | 33 | 34 | -------------------------------------------------------------------------------- /StemsAnalyser/StemsAnalyser.roboFontExt/lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sansplomb/RobofontTools/9e5b99bde35b98041ce0a36dc87c8ea058ef2aa1/StemsAnalyser/StemsAnalyser.roboFontExt/lib/.DS_Store -------------------------------------------------------------------------------- /StemsAnalyser/StemsAnalyser.roboFontExt/lib/StemsAnalyser.py: -------------------------------------------------------------------------------- 1 | from mojo.events import * 2 | from mojo.drawingTools import * 3 | from vanilla import * 4 | from defconAppKit.windows.baseWindow import BaseWindowController 5 | from AppKit import * 6 | 7 | import math 8 | import StemsAnalyserModule as module 9 | 10 | minStemX = 20 11 | minStemY = 20 12 | maxStemX = 400 13 | maxStemY = 400 14 | 15 | class WindowController(BaseWindowController): 16 | 17 | def __init__(self): 18 | self.w = FloatingWindow((400, 240), "Stems Analyser") 19 | self.w.roundTo5CheckBox = CheckBox((10, 20, -10, 20), "Round Values to 5", 20 | callback=self.roundTo5CheckBoxCallback, value=True) 21 | self.w.startButton = Button((10, 50, 170, 30), "Analyse Selected Glyphs", callback=self.startButtonCallBack) 22 | self.w.xTextBox = TextBox((10, 90, -10, 17), "Horizontal (Y):") 23 | self.w.xValuesEditText = TextBox((10, 110, -10, 22)) 24 | self.w.yTextBox = TextBox((10, 140, -10, 17), "Vertical (X):") 25 | self.w.yValuesEditText = TextBox((10, 160, -10, 22)) 26 | self.w.applyButton = Button((10, 200, 190, 30), "Copy to PS StemsSnap", callback=self.applyButtonCallBack) 27 | self.w.stopButton = Button((210, 200, -10, 30), "Close", callback=self.stopButtonCallBack) 28 | self.w.open() 29 | 30 | self.roundTo5 = 1 31 | self.stemSnapHList = [] 32 | self.stemSnapVList = [] 33 | 34 | # create a background color 35 | self.backgroundColorX = NSColor.redColor() 36 | self.backgroundColorY = NSColor.blackColor() 37 | # create a background stroke color 38 | self.backgroundStrokeColor = NSColor.whiteColor() 39 | # create a stroke color 40 | self.strokeColorX = NSColor.redColor() 41 | self.strokeColorY = NSColor.blackColor() 42 | # setting text attributes 43 | self.attributes = attributes = { 44 | NSFontAttributeName : NSFont.boldSystemFontOfSize_(9), 45 | NSForegroundColorAttributeName : NSColor.whiteColor(), 46 | } 47 | def roundTo5CheckBoxCallback(self, sender): 48 | self.roundTo5 = sender.get() 49 | 50 | def applyButtonCallBack(self, sender): 51 | f.info.postscriptStemSnapH = self.stemSnapHList 52 | f.info.postscriptStemSnapV = self.stemSnapVList 53 | 54 | def draw(self, notification): 55 | glyph = notification["glyph"] 56 | for gStems in self.glyphsStemsList: 57 | if gStems[0] == glyph.name: 58 | view = notification["view"] 59 | scale = notification["scale"] 60 | pathX = NSBezierPath.bezierPath() 61 | pathY = NSBezierPath.bezierPath() 62 | 63 | valuesListX = [] 64 | for stem in gStems[1]: 65 | startPoint_x = stem[0].x 66 | startPoint_y = stem[0].y 67 | endPoint_x = stem[1].x 68 | endPoint_y = stem[1].y 69 | length = float(stem[2][0]) 70 | pathX.moveToPoint_((startPoint_x, startPoint_y)) 71 | pathX.lineToPoint_((endPoint_x, endPoint_y)) 72 | center_x = startPoint_x + (endPoint_x - startPoint_x) * 0.5 73 | center_y = startPoint_y + (endPoint_y - startPoint_y) * 0.5 74 | valuesListX.append((center_x, center_y, length)) 75 | # set the stroke color 76 | self.strokeColorX.set() 77 | # set the line width of the path 78 | pathX.setLineWidth_(scale) 79 | # stroke the path 80 | pathX.stroke() 81 | 82 | for x, y, lengthValue in valuesListX: 83 | if lengthValue.is_integer(): 84 | t = "%i" 85 | else: 86 | t = "%.2f" 87 | view._drawTextAtPoint(t % lengthValue, self.attributes, (x, y), drawBackground=True, backgroundColor=self.backgroundColorX, backgroundStrokeColor=self.backgroundStrokeColor) 88 | 89 | valuesListY = [] 90 | for stem in gStems[2]: 91 | startPoint_x = stem[0].x 92 | startPoint_y = stem[0].y 93 | endPoint_x = stem[1].x 94 | endPoint_y = stem[1].y 95 | length = float(stem[2][1]) 96 | pathY.moveToPoint_((startPoint_x, startPoint_y)) 97 | pathY.lineToPoint_((endPoint_x, endPoint_y)) 98 | center_x = startPoint_x + (endPoint_x - startPoint_x) * 0.5 99 | center_y = startPoint_y + (endPoint_y - startPoint_y) * 0.5 100 | valuesListY.append((center_x, center_y, length)) 101 | # set the stroke color 102 | self.strokeColorY.set() 103 | # set the line width of the path 104 | pathY.setLineWidth_(scale) 105 | # stroke the path 106 | pathY.stroke() 107 | 108 | for x, y, lengthValue in valuesListY: 109 | if lengthValue.is_integer(): 110 | t = "%i" 111 | else: 112 | t = "%.2f" 113 | view._drawTextAtPoint(t % lengthValue, self.attributes, (x, y), drawBackground=True, backgroundColor=self.backgroundColorY, backgroundStrokeColor=self.backgroundStrokeColor) 114 | 115 | 116 | def startButtonCallBack(self, sender): 117 | 118 | self.glyphsStemsList = [] 119 | 120 | self.w.xValuesEditText.set('') 121 | self.w.yValuesEditText.set('') 122 | self.stemsValuesXList = [] 123 | self.stemsValuesYList = [] 124 | self.stemSnapHList = [] 125 | self.stemSnapVList = [] 126 | roundedStemsXList = [] 127 | roundedStemsYList = [] 128 | originalStemsXList = [] 129 | originalStemsYList = [] 130 | 131 | 132 | self.f = CurrentFont() 133 | if self.f.info.italicAngle != None: 134 | self.ital = - self.f.info.italicAngle 135 | else: 136 | self.ital = 0 137 | self.progress = self.startProgress("Preparing") 138 | tickCount = 0 139 | for g in self.f: 140 | if g.selected: 141 | tickCount += 1 142 | 143 | self.progress.setTickCount(tickCount) 144 | self.progress.update("Analysing Selected Glyphs") 145 | for g in self.f: 146 | if g.selected: 147 | self.g_hPoints = make_hPointsList(g) 148 | (self.stemsListX, self.stemsListY) = makeStemsList(self.f, self.g_hPoints, g, self.ital) 149 | if self.roundTo5 == 1: 150 | for stem in self.stemsListX: 151 | roundedStemsXList.append(module.roundbase(stem[2][0], 5)) 152 | for stem in self.stemsListY: 153 | roundedStemsYList.append(module.roundbase(stem[2][1], 5)) 154 | 155 | self.stemsValuesXList = roundedStemsXList 156 | self.stemsValuesYList = roundedStemsYList 157 | 158 | self.glyphsStemsList.append((g.name, self.stemsListX, self.stemsListY)) 159 | 160 | else: 161 | for stem in self.stemsListX: 162 | originalStemsXList.append(stem[2][0]) 163 | for stem in self.stemsListY: 164 | originalStemsYList.append(stem[2][1]) 165 | 166 | self.stemsValuesXList = originalStemsXList 167 | self.stemsValuesYList = originalStemsYList 168 | 169 | self.glyphsStemsList.append((g.name, self.stemsListX, self.stemsListY)) 170 | 171 | self.progress.update() 172 | 173 | 174 | self.progress.setTickCount(0) 175 | self.progress.update("Sorting Values") 176 | 177 | valuesXDict = {} 178 | for StemXValue in self.stemsValuesXList: 179 | try: 180 | valuesXDict[StemXValue] += 1 181 | except KeyError: 182 | valuesXDict[StemXValue] = 1 183 | #print 'x',valuesXDict 184 | 185 | valuesYDict = {} 186 | for StemYValue in self.stemsValuesYList: 187 | try: 188 | valuesYDict[StemYValue] += 1 189 | except KeyError: 190 | valuesYDict[StemYValue] = 1 191 | #print 'y',valuesYDict 192 | 193 | keyValueXList = valuesXDict.items() 194 | keyValueXList.sort(module.compare) 195 | keyValueXList = keyValueXList[:12] 196 | 197 | keyValueYList = valuesYDict.items() 198 | keyValueYList.sort(module.compare) 199 | keyValueYList = keyValueYList[:12] 200 | 201 | 202 | for keyValue in keyValueXList: 203 | self.stemSnapVList.append(keyValue[0]) 204 | #print 'stemSnapH', self.stemSnapHList 205 | 206 | stemSnapVText = '' 207 | for i in self.stemSnapVList: 208 | stemSnapVText += str(i) + ' ' 209 | self.w.yValuesEditText.set(stemSnapVText) 210 | 211 | for keyValue in keyValueYList: 212 | self.stemSnapHList.append(keyValue[0]) 213 | #print 'stemSnapV', self.stemSnapVList 214 | 215 | stemSnapHText = '' 216 | for i in self.stemSnapHList: 217 | stemSnapHText += str(i) + ' ' 218 | self.w.xValuesEditText.set(stemSnapHText) 219 | 220 | 221 | 222 | addObserver(self, "draw", "draw") 223 | 224 | self.progress.close() 225 | 226 | 227 | def stopButtonCallBack(self, sender): 228 | removeObserver(self, "draw") 229 | self.w.close() 230 | 231 | ################### 232 | 233 | def make_hPointsList(g): 234 | contoursList = [] 235 | hPointsList = [] 236 | for i in range(len(g)): 237 | pointsList = [] 238 | for j in g[i].points: 239 | pointsList.append(j) 240 | contoursList.append(pointsList) 241 | 242 | for contour_index in range(len(contoursList)): 243 | for point_index in range(len(contoursList[contour_index])): 244 | currentPoint = contoursList[contour_index][point_index] 245 | if point_index == 0: 246 | prevPoint = contoursList[contour_index][len(contoursList[contour_index])-1] 247 | else: 248 | prevPoint = contoursList[contour_index][point_index-1] 249 | if point_index == len(contoursList[contour_index]) -1: 250 | nextPoint = contoursList[contour_index][0] 251 | else: 252 | nextPoint = contoursList[contour_index][point_index+1] 253 | 254 | if currentPoint.type != 'offCurve': 255 | directionIN = module.direction(prevPoint, currentPoint) 256 | directionOUT = module.direction(currentPoint, nextPoint) 257 | vectorIN = module.angle(prevPoint, currentPoint) 258 | vectorOUT = module.angle(currentPoint, nextPoint) 259 | 260 | hPoint = (currentPoint, contour_index, point_index, directionIN, directionOUT, vectorIN, vectorOUT) 261 | hPointsList.append(hPoint) 262 | return hPointsList 263 | 264 | def getColor(point1, point2, g): 265 | hasSomeBlack = False 266 | hasSomeWhite = False 267 | color = '' 268 | if abs(point2.x - point1.x) < maxStemX or abs(point2.y - point1.y) < maxStemY: 269 | hypothLength = int(module.hypothenuse(point1, point2)) 270 | for j in range(1, hypothLength-1): 271 | cp_x = point1.x + ((j)/hypothLength)*(point2.x - point1.x) 272 | cp_y = point1.y + ((j)/hypothLength)*(point2.y - point1.y) 273 | if g.pointInside((cp_x, cp_y)): 274 | hasSomeBlack = True 275 | else: 276 | hasSomeWhite = True 277 | if hasSomeBlack and hasSomeWhite: 278 | break 279 | 280 | if hasSomeBlack and hasSomeWhite: 281 | color = 'Gray' 282 | elif hasSomeBlack: 283 | color = 'Black' 284 | else: 285 | color = 'White' 286 | return color 287 | 288 | 289 | 290 | def makeStemsList(f, g_hPoints, g, italicAngle): 291 | stemsListX_temp = [] 292 | stemsListY_temp = [] 293 | stemsListX = [] 294 | stemsListY = [] 295 | for source_hPoint in range(len(g_hPoints)): 296 | for target_hPoint in range(len(g_hPoints)): 297 | sourcePoint = g_hPoints[source_hPoint][0] 298 | targetPoint = g_hPoints[target_hPoint][0] 299 | directionIn_source = g_hPoints[source_hPoint][3] 300 | directionOut_source = g_hPoints[source_hPoint][4] 301 | directionIn_target = g_hPoints[target_hPoint][3] 302 | directionOut_target = g_hPoints[target_hPoint][4] 303 | angleIn_source = g_hPoints[source_hPoint][5] 304 | angleOut_source = g_hPoints[source_hPoint][6] 305 | angleIn_target = g_hPoints[target_hPoint][5] 306 | angleOut_target = g_hPoints[target_hPoint][6] 307 | color = getColor(sourcePoint, targetPoint, g) 308 | if color == 'Black': 309 | c_distance = module.distance(sourcePoint, targetPoint) 310 | stem = (sourcePoint, targetPoint, c_distance) 311 | hypoth = module.hypothenuse(sourcePoint, targetPoint) 312 | ## if Source and Target are almost aligned 313 | # closeAngle(angleIn_source, angleIn_target) or closeAngle(angleOut_source, angleOut_target) or 314 | if module.closeAngle(angleIn_source, angleOut_target) or module.closeAngle(angleOut_source, angleIn_target): 315 | ## if Source and Target have opposite direction 316 | if module.opposite(directionIn_source, directionIn_target) or module.opposite(directionIn_source, directionOut_target) or module.opposite(directionOut_source, directionIn_target): 317 | 318 | ## if they are horizontal, treat the stem on the Y axis 319 | if (module.isHorizontal(angleIn_source) or module.isHorizontal(angleOut_source)) and (module.isHorizontal(angleIn_target) or module.isHorizontal(angleOut_target)): 320 | if (minStemY - 20*(minStemY/100) < c_distance[1] < maxStemY + 20*(maxStemY/100)) and (minStemY - 20*(minStemY/100) <= hypoth <= maxStemY + 20*(maxStemY/100)): 321 | stemsListY_temp.append(stem) 322 | 323 | ## if they are vertical, treat the stem on the X axis 324 | if (module.isVertical(angleIn_source) or module.isVertical(angleOut_source)) and (module.isVertical(angleIn_target) or module.isVertical(angleOut_target)): 325 | 326 | if (minStemX - 20*(minStemX/100) <= c_distance[0] <= maxStemX + 20*(maxStemX/100)) and (minStemX - 20*(minStemX/100)<= hypoth <= maxStemX + 20*(maxStemX/100)): 327 | stemsListX_temp.append(stem) 328 | # avoid duplicates, filters temporary stems 329 | yList = [] 330 | for stem in stemsListY_temp: 331 | def pred0(y): 332 | return module.approxEqual(stem[0].y, y) 333 | def pred1(y): 334 | return module.approxEqual(stem[1].y, y) 335 | if not module.exists(yList, pred0) or not module.exists(yList, pred1): 336 | stemsListY.append(stem) 337 | yList.append(stem[0].y) 338 | yList.append(stem[1].y) 339 | 340 | xList = [] 341 | for stem in stemsListX_temp: 342 | (preRot0x, preRot0y) = module.rotated(stem[0], italicAngle) 343 | (preRot1x, preRot1y) = module.rotated(stem[1], italicAngle) 344 | def pred0(x): 345 | #print preRot0x, x 346 | return module.approxEqual(preRot0x, x) 347 | def pred1(x): 348 | #print preRot1x, x 349 | return module.approxEqual(preRot1x, x) 350 | if not module.exists(xList,pred0) or not module.exists(xList,pred1): 351 | stemsListX.append(stem) 352 | xList.append(preRot0x) 353 | xList.append(preRot1x) 354 | 355 | return (stemsListX, stemsListY) 356 | 357 | 358 | ################ 359 | 360 | f = CurrentFont() 361 | if f.info.italicAngle != None: 362 | ital = - f.info.italicAngle 363 | else: 364 | ital = 0 365 | 366 | g = f['o'] 367 | if not g: 368 | print "WARNING: glyph 'o' missing" 369 | o_hPoints = make_hPointsList(g) 370 | (o_stemsListX, o_stemsListY) = makeStemsList(f, o_hPoints, g, ital) 371 | 372 | g = f['O'] 373 | if not g: 374 | print "WARNING: glyph 'O' missing" 375 | O_hPoints = make_hPointsList(g) 376 | (O_stemsListX, O_stemsListY) = makeStemsList(f, O_hPoints, g, ital) 377 | 378 | Xs = [] 379 | for i in O_stemsListX: 380 | Xs.append(i[2][0]) 381 | maxX = max(Xs) 382 | 383 | Ys = [] 384 | for i in o_stemsListY: 385 | Ys.append(i[2][1]) 386 | minY = min(Ys) 387 | 388 | 389 | minStemX = minY - 30*(minY/100) 390 | minStemY = minY - 30*(minY/100) 391 | 392 | maxStemX = maxX + 10*(maxX/100) 393 | maxStemY = maxX + 10*(maxX/100) 394 | 395 | 396 | #print 'minX', minStemX, 'maxX', maxStemX 397 | #print 'minY', minStemY, 'maxY', maxStemY 398 | ################ 399 | 400 | reload(module) 401 | 402 | WindowController() 403 | -------------------------------------------------------------------------------- /StemsAnalyser/StemsAnalyser.roboFontExt/lib/StemsAnalyserModule.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def direction(point1, point2): 4 | direction_x = 4 5 | direction_y = 4 6 | if point1.x < point2.x: 7 | # Direction is RIGHT 8 | direction_x = 1 9 | elif point1.x > point2.x: 10 | # Direction is LEFT 11 | direction_x = -1 12 | else: 13 | # Direction is NONE 14 | direction_x = 4 15 | 16 | if point1.y < point2.y: 17 | # Direction is UP 18 | direction_y = 1 19 | elif point1.y > point2.y: 20 | # Direction is DOWN 21 | direction_y = -1 22 | else: 23 | # Direction is NONE 24 | direction_y = 4 25 | return (direction_x, direction_y) 26 | 27 | 28 | def rotated(point, angle): 29 | x = point.x 30 | y = point.y 31 | angle = (math.radians(angle)) 32 | cosa = math.cos(angle) 33 | sina = math.sin(angle) 34 | rotatedPoint_x = int(cosa*x - sina*y) 35 | rotatedPoint_y = int(sina*x + cosa*y) 36 | return (rotatedPoint_x, rotatedPoint_y) 37 | 38 | 39 | def angle(point1, point2): 40 | return math.atan2(point2.y - point1.y, point2.x - point1.x) / math.pi * 180 41 | 42 | def shearFactor(angle): 43 | # find the shearFactor r with a given angle 44 | r = math.tan(math.radians(angle)) 45 | return r 46 | 47 | def distance(point1, point2): 48 | return (abs(point1.x - point2.x), abs(point1.y - point2.y)) 49 | 50 | def hypothenuse(point1, point2): 51 | return math.sqrt(distance(point1, point2)[0]*distance(point1, point2)[0] + distance(point1, point2)[1]*distance(point1, point2)[1]) 52 | 53 | def closeAngle(angle1, angle2): 54 | diff = angle1 - angle2 55 | while diff >= 90: 56 | diff -= 180 57 | while diff < -90: 58 | diff += 180 59 | return (abs(diff)<5) 60 | 61 | def approxEqual(a1, a2): 62 | #return abs(a1 - a2) < 10*(abs(a1)/100) 63 | return ( abs(a1 - a2) <= 10*(abs(a1)/100) ) 64 | 65 | def opposite(direction1, direction2): 66 | isOpposite = False 67 | LR1 = direction1[0] 68 | UD1 = direction1[1] 69 | LR2 = direction2[0] 70 | UD2 = direction2[1] 71 | if LR1 + LR2 == 0: 72 | isOpposite = True 73 | if UD1 + UD2 == 0: 74 | isOpposite = True 75 | return isOpposite 76 | 77 | def isVertical(vector): 78 | vector = abs(vector) 79 | if ((65 < vector) and (vector < 115)): 80 | return True 81 | else: 82 | return False 83 | 84 | def isHorizontal(vector): 85 | vector = abs(vector) 86 | if ((0 <= vector) and (vector <= 45)) or ((135 <= vector) and (vector <= 180)): 87 | return True 88 | else: 89 | return False 90 | 91 | #True si il existe un element de la liste l pour lequel la fonction p renvoi True (on dit que le predicat p est vrai sur cet element) 92 | def exists(l, p): 93 | for e in l: 94 | if p(e): 95 | return True 96 | return False 97 | 98 | def sheared(point, angle): 99 | r = shearFactor(angle) 100 | return (point.x + r*point.y, point.y) 101 | 102 | def roundbase(x, base): 103 | return int(base * round(float(x)/base)) 104 | 105 | def compare((k1,v1),(k2,v2)): 106 | return v2 - v1 107 | 108 | ###### -------------------------------------------------------------------------------- /Tests/Convert2Quadratic.py: -------------------------------------------------------------------------------- 1 | from lib.tools.bezierTools import curveConverter 2 | import copyFontInfos as CFI 3 | import os 4 | reload(CFI) 5 | 6 | def Convert2Quadratic(f, RemoveOverlap=False): 7 | currentpath = f.path 8 | root, tail = os.path.split(f.path) 9 | QuadraticUFOTail = 'Quatratic_' + tail.split('.')[0] + '.ufo' 10 | QuadraticUFOPath = os.path.join(root, QuadraticUFOTail) 11 | 12 | nf = NewFont() 13 | nf.preferredSegmentType = "qCurve" 14 | CFI.copyAllInfoFromTo(f, nf) 15 | for g in f: 16 | nf[g.name] = g.copy() 17 | for g in nf: 18 | if RemoveOverlap: 19 | g.removeOverlap() 20 | mask = g.getLayer("CubicContour") 21 | mask.clear() 22 | g.copyToLayer("CubicContour") 23 | glyphNaked = g.naked() 24 | 25 | if curveConverter.isBezier(glyphNaked): 26 | curveConverter.bezier2quadratic(glyphNaked) 27 | glyphNaked.correctDirection(trueType=True) 28 | 29 | nf.save(QuadraticUFOPath) 30 | 31 | f = CurrentFont() 32 | Convert2Quadratic(f, True) -------------------------------------------------------------------------------- /Tests/copyFontInfos.py: -------------------------------------------------------------------------------- 1 | fontInfoAttributes = [ 2 | 'ascender', 3 | 'capHeight', 4 | 'copyright', 5 | 'descender', 6 | 'familyName', 7 | 'italicAngle', 8 | 'macintoshFONDFamilyID', 9 | 'macintoshFONDName', 10 | 'note', 11 | 'openTypeHeadCreated', 12 | 'openTypeHeadFlags', 13 | 'openTypeHeadLowestRecPPEM', 14 | 'openTypeHheaAscender', 15 | 'openTypeHheaCaretOffset', 16 | 'openTypeHheaCaretSlopeRise', 17 | 'openTypeHheaCaretSlopeRun', 18 | 'openTypeHheaDescender', 19 | 'openTypeHheaLineGap', 20 | 'openTypeNameCompatibleFullName', 21 | 'openTypeNameDescription', 22 | 'openTypeNameDesigner', 23 | 'openTypeNameDesignerURL', 24 | 'openTypeNameLicense', 25 | 'openTypeNameLicenseURL', 26 | 'openTypeNameManufacturer', 27 | 'openTypeNameManufacturerURL', 28 | 'openTypeNamePreferredFamilyName', 29 | 'openTypeNamePreferredSubfamilyName', 30 | 'openTypeNameSampleText', 31 | 'openTypeNameUniqueID', 32 | 'openTypeNameVersion', 33 | 'openTypeNameWWSFamilyName', 34 | 'openTypeNameWWSSubfamilyName', 35 | 'openTypeOS2CodePageRanges', 36 | 'openTypeOS2FamilyClass', 37 | 'openTypeOS2Panose', 38 | 'openTypeOS2Selection', 39 | 'openTypeOS2StrikeoutPosition', 40 | 'openTypeOS2StrikeoutSize', 41 | 'openTypeOS2SubscriptXOffset', 42 | 'openTypeOS2SubscriptXSize', 43 | 'openTypeOS2SubscriptYOffset', 44 | 'openTypeOS2SubscriptYSize', 45 | 'openTypeOS2SuperscriptXOffset', 46 | 'openTypeOS2SuperscriptXSize', 47 | 'openTypeOS2SuperscriptYOffset', 48 | 'openTypeOS2SuperscriptYSize', 49 | 'openTypeOS2Type', 50 | 'openTypeOS2TypoAscender', 51 | 'openTypeOS2TypoDescender', 52 | 'openTypeOS2TypoLineGap', 53 | 'openTypeOS2UnicodeRanges', 54 | 'openTypeOS2VendorID', 55 | 'openTypeOS2WeightClass', 56 | 'openTypeOS2WidthClass', 57 | 'openTypeOS2WinAscent', 58 | 'openTypeOS2WinDescent', 59 | 'openTypeVheaCaretOffset', 60 | 'openTypeVheaCaretSlopeRise', 61 | 'openTypeVheaCaretSlopeRun', 62 | 'openTypeVheaVertTypoAscender', 63 | 'openTypeVheaVertTypoDescender', 64 | 'openTypeVheaVertTypoLineGap', 65 | 'postscriptBlueFuzz', 66 | 'postscriptBlueScale', 67 | 'postscriptBlueShift', 68 | 'postscriptBlueValues', 69 | 'postscriptDefaultCharacter', 70 | 'postscriptDefaultWidthX', 71 | 'postscriptFamilyBlues', 72 | 'postscriptFamilyOtherBlues', 73 | 'postscriptFontName', 74 | 'postscriptForceBold', 75 | 'postscriptFullName', 76 | 'postscriptIsFixedPitch', 77 | 'postscriptNominalWidthX', 78 | 'postscriptOtherBlues', 79 | 'postscriptSlantAngle', 80 | 'postscriptStemSnapH', 81 | 'postscriptStemSnapV', 82 | 'postscriptUnderlinePosition', 83 | 'postscriptUnderlineThickness', 84 | 'postscriptUniqueID', 85 | 'postscriptWeightName', 86 | 'postscriptWindowsCharacterSet', 87 | 'styleMapFamilyName', 88 | 'styleMapStyleName', 89 | 'styleName', 90 | 'trademark', 91 | 'unitsPerEm', 92 | 'versionMajor', 93 | 'versionMinor', 94 | 'xHeight', 95 | 'year'] 96 | 97 | 98 | def copyAllInfoFromTo(f, nf): 99 | for attr in fontInfoAttributes: 100 | value = f.info.__getattr__(attr) 101 | nf.info.__setattr__(attr, value) 102 | --------------------------------------------------------------------------------