├── 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 |
--------------------------------------------------------------------------------