def checkFont(self, useSelection=False, excludeZeroWidth=True): f = CurrentFont() if f is not None: # initialize things self.w.options.progress.start() time0 = time.time() self.excludeZeroWidth = excludeZeroWidth self.f = f glyphNames = f.selection if useSelection else f.keys() glyphList = [f[x] for x in glyphNames] glyphList = self._trimGlyphList(glyphList) self.touchingPairs = Touche(f).findTouchingPairs(glyphList) # display output self.w.results.stats.set("%d glyphs checked" % len(glyphList)) self.w.results.result.set("%d touching pairs found" % len(self.touchingPairs)) self.w.results.show(True) outputList = [{"left glyph": g1, "right glyph": g2} for (g1, g2) in self.touchingPairs] self.w.outputList.set(outputList) if len(self.touchingPairs) > 0: self.w.outputList.setSelection([0]) #self.w.preview.setFont(f) self.w.options.progress.stop() self._resizeWindow(enlarge=True) time1 = time.time() print u'Touché: finished checking %d glyphs in %.2f seconds' % (len(glyphList), time1-time0) else: Message(u'Touché: Can’t find a font to check')
def moveAnchor(distancia, sentido, anchorName): f = CurrentFont() if anchorName != '': for g in f: if g.selected: if len(g.anchors) > 0: setAnchor(g, distancia, sentido, anchorName) else: print 'No hay anchors' f.update() else: print "Debe declarar un nombre de anchor primero."
def expandSelection(self, sender): font = CurrentFont() preserveComponents = bool(self.w.preserveComponents.get()) selection = font.selection for glyphName in selection: glyph = font[glyphName] self.expandGlyph(glyph, preserveComponents)
def sortWordsByWidth(self, wordlist): """Sort output word list by width.""" f = CurrentFont() wordWidths = [] for word in wordlist: unitCount = 0 for char in word: try: glyphWidth = f[char].width except: try: gname = self.glyphNamesForValues[char] glyphWidth = f[gname].width except: glyphWidth = 0 unitCount += glyphWidth # add kerning for i in range(len(word) - 1): pair = list(word[i:i + 2]) unitCount += int(self.findKerning(pair)) wordWidths.append(unitCount) wordWidths_sorted, wordlist_sorted = zip(*sorted( zip(wordWidths, wordlist))) # thanks, stackoverflow return wordlist_sorted
def alignToptoAscenderFunction(paths): font = CurrentFont() mm = minmaxPaths(paths) paths = [ path.applyPlus(TFSPoint(0, font.info.ascender - mm.maxY)) for path in paths ] return paths
def checkFont(self, useSelection=False, excludeZeroWidth=True): f = CurrentFont() if f is not None: # initialize things self.w.options.progress.start() time0 = time.time() self.excludeZeroWidth = excludeZeroWidth self.f = f glyphNames = f.selection if useSelection else f.keys() glyphList = [f[x] for x in glyphNames] glyphList = self._trimGlyphList(glyphList) self.touchingPairs = Touche(f).findTouchingPairs(glyphList) # display output self.w.results.stats.set("%d glyphs checked" % len(glyphList)) self.w.results.result.set("%d touching pairs found" % len(self.touchingPairs)) self.w.results.show(True) outputList = [{"left glyph": g1, "right glyph": g2} for (g1, g2) in self.touchingPairs] outputStringList = [ "/%s/%s " % (g1, g2) for (g1, g2) in self.touchingPairs ] outputStringMetalist = [outputStringList[i:i + 400] for i in range(0, len(outputStringList), 400)] ActiveFont = self.f._font ActiveFont.disableUpdateInterface() for eachList in outputStringMetalist: outputString = "".join(eachList) ActiveFont.newTab(outputString) self.w.outputList.set(outputList) if len(self.touchingPairs) > 0: self.w.outputList.setSelection([0]) ActiveFont.enableUpdateInterface() #self.w.preview.setFont(f) self.w.options.progress.stop() self._resizeWindow(enlarge=True) time1 = time.time() print u'Touché: finished checking %d glyphs in %.2f seconds' % (len(glyphList), time1-time0) else: Message(u'Touché: Can’t find a font to check')
def fontSelectionCallback(self, sender): font = CurrentFont() if font is None: return self.selectedGlyphs = list(font.selection) self.unselectedGlyphs = list( set(self.allGlyphs) - set(self.selectedGlyphs)) self.unselectedGlyphs.sort() self._updateLists()
def run_exportFLK(self, sender): font = CurrentFont() if font != None: ufopath = getUFOpath(font) if ufopath != None: exportKerningFL(font, ufopath) else: print 'Please, open any .vfb with kerning :)' self.w.close()
def centerBelowAscenderFunction(paths): font = CurrentFont() mm = minmaxPaths(paths) paths = [ path.applyPlus( TFSPoint(0, (font.info.ascender - (mm.maxY - mm.minY)) * 0.5)) for path in paths ] return paths
def apply_callback(self, sender): self.font = CurrentFont() if self.font is not None: gNames = getGlyphs(self.font) if len(gNames) > 0: # print info if self._verbose: print 'rounding glyphs to grid...\n' print '\tgrid size: %s' % self._gridsize print '\tpoints: %s' % self._points print '\tanchors: %s' % self._anchors print '\tside-bearings: %s' % self._sidebearings print '\tmark: %s' % self._mark print print '\t', # batch process glyphs for gName in gNames: print gName, if self._points: roundPointsToGrid(self.font[gName], (self._gridsize, self._gridsize)) if self._anchors: roundAnchorsToGrid(self.font[gName], (self._gridsize, self._gridsize)) if self._sidebearings: roundMargins(self.font[gName], self._gridsize, left=True, right=True) if self._mark: self.font[gName].mark = self._mark_color self.font[gName].update() # done print self.font.update() if self._verbose: print '\n...done.\n' # no glyphs selected else: print 'no glyph to process, please select one or more glyphs and try again.\n' # no font open else: print 'please open a font and try again.\n'
def apply_Callback(self, sender): f = CurrentFont() if f is not None: print 'processing selected glyphs...\n' # get options boolstring = [False, True] _points = self.w._points_checkBox.get() _sidebearings = self.w._sidebearings_checkBox.get() _anchors = self.w._anchors_checkBox.get() # get color _gridsize = int(self.w._gridsize_value.get()) _mark = self.w._mark_checkBox.get() _mark_color = self.w._mark_color.get() _mark_color = (_mark_color.redComponent(), _mark_color.greenComponent(), _mark_color.blueComponent(), _mark_color.alphaComponent()) print '\tgrid size: %s' % _gridsize print '\talign points to grid: %s' % boolstring[_points] print '\talign side-bearings: %s' % boolstring[_sidebearings] print '\talign anchors: %s' % boolstring[_anchors] print '\tmark glyphs: %s (%s)' % (boolstring[_mark], _mark_color) print print '\t', # batch do stuff for gName in f.selection: print gName, f[gName].prepareUndo('align to grid') if _points: roundPointsToGrid(f[gName], (_gridsize, _gridsize)) if _anchors: roundAnchorsToGrid(f[gName], (_gridsize, _gridsize)) if _sidebearings: roundMargins(f[gName], _gridsize, left=True, right=True) if _mark: f[gName].mark = _mark_color f[gName].update() f[gName].performUndo() # done print f.update() print '\n...done.\n'
def _updateExportFileList(self): if self.w.exportCurrentFontCheckBox.get(): font = CurrentFont() if font is None: self.files = {} else: self.files = {font.path: font} else: self.files = {} for font in AllFonts(): self.files[font.path] = font self._updateFileList()
def checkFont(self, useSelection=False, excludeZeroWidth=True): f = CurrentFont() if f is not None: # initialize things self.w.options.progress.start() time0 = time.time() self.excludeZeroWidth = excludeZeroWidth self.f = f glyphNames = f.selection if useSelection else f.keys() glyphList = [f[x] for x in glyphNames] glyphList = self._trimGlyphList(glyphList) self.touchingPairs = Touche(f).findTouchingPairs(glyphList) # display output self.w.results.stats.set("%d glyphs checked" % len(glyphList)) self.w.results.result.set("%d touching pairs found" % len(self.touchingPairs)) self.w.results.show(True) outputList = [{ "left glyph": g1, "right glyph": g2 } for (g1, g2) in self.touchingPairs] self.w.outputList.set(outputList) if len(self.touchingPairs) > 0: self.w.outputList.setSelection([0]) #self.w.preview.setFont(f) self.w.options.progress.stop() self._resizeWindow(enlarge=True) time1 = time.time() print('Touché: finished checking %d glyphs in %.2f seconds' % (len(glyphList), time1 - time0)) else: Message('Touché: Can’t find a font to check')
def draw(self): # canvas draw callback drawing.save() self._drawGrid() drawing.restore() font = CurrentFont() if self.show_fixed and self.system is not None and self.system.fixed_units: # display the fixed widths of the current unitization system self.draw_histogram(font, self.system.upm, (0, 0, 1, 0.5), True, histogram=self.system.fixed_units) # draw the histogram for the current font print "__font:", font print "__font.info:", font.info self.draw_histogram(font, font.info.unitsPerEm, (1, 0, 0, 1), True)
def loadPrefs(self): """Load the saved preferences into the program.""" self.requiredLetters = [] self.requiredGroups = [[], [], []] self.banRepetitions = False # preset character groups self.groupPresets = [["[lc] Ascenders", ["b", "f", "h", "k", "l"]], ["[lc] Descenders", ["g", "j", "p", "q", "y"]], ["[lc] Ball-and-Stick", ["b", "d", "p", "q"]], ["[lc] Arches", ["n", "m", "h", "u"]], ["[lc] Diagonals", ["v", "w", "x", "y"]]] # define initial values initialDefaults = { "com.ninastoessinger.word-o-mat.wordCount": 20, "com.ninastoessinger.word-o-mat.minLength": 3, "com.ninastoessinger.word-o-mat.maxLength": 15, "com.ninastoessinger.word-o-mat.case": 0, "com.ninastoessinger.word-o-mat.limitToCharset": "True", "com.ninastoessinger.word-o-mat.source": 0, "com.ninastoessinger.word-o-mat.matchMode": "text", "com.ninastoessinger.word-o-mat.matchPattern": "", "com.ninastoessinger.word-o-mat.markColor": "None", } registerExtensionDefaults(initialDefaults) # load prefs into variables/properties prefsToLoad = { "wordCount": "com.ninastoessinger.word-o-mat.wordCount", "minLength": "com.ninastoessinger.word-o-mat.minLength", "maxLength": "com.ninastoessinger.word-o-mat.maxLength", "case": "com.ninastoessinger.word-o-mat.case", "matchMode": "com.ninastoessinger.word-o-mat.matchMode", "matchPattern": "com.ninastoessinger.word-o-mat.matchPattern", "reqMarkColor": "com.ninastoessinger.word-o-mat.markColor", } for variableName, pref in prefsToLoad.iteritems(): setattr(self, variableName, getExtensionDefault(pref)) # restore booleans from strings limitPref = "com.ninastoessinger.word-o-mat.limitToCharset" self.limitToCharset = self.readExtDefaultBoolean( getExtensionDefault(limitPref)) if CurrentFont() else False # parse mark color pref # print "***", self.reqMarkColor if self.reqMarkColor is not "None": if type(self.reqMarkColor) is tuple: self.reqMarkColor = tuple(float(i) for i in self.reqMarkColor) else: self.reqMarkColor = "None"
def wrapGlyphs(self): glyphs = [] f = CurrentFont() if f is None: return names = f.keys() names.sort() # layers = f.layerOrder # if 'bounds' in layers: # hasBounds = "yup" # else: hasBounds = "nope" for n in names: if n in self.masterNames: status = True else: continue g = f[n] gb = g.getLayer('bounds') if gb: xMin, yMin, xMax, yMax = gb.box width = xMax-xMin height = yMax-yMin else: width = g.width height = None contours, points = self.countGlyph(g) d = dict(name=g.name, width=width, height=height, bounds=hasBounds, status=status, contours=contours, points=points, ) glyphs.append(d) return glyphs
def get_glyphnames_for_histogram(self): font = CurrentFont() mode = self.w.glyph_selection.get() if mode == 0: #print "Analyze Selection" names = font.selection elif mode == 1: #print "Analyze All Glyphs" names = font.glyphOrder print "__Names:", names else: #print "Analyze Charset" all_glyphs = font.glyphOrder selected_charset_name = self.w.charset_selection.getItems()[self.w.charset_selection.get()] names = [name for name in self.charsets[selected_charset_name] if name in all_glyphs] return names
def run(): f = CurrentFont() if f != None: myPath = os.path.dirname(f.path) fdkPath = setDirectory(myPath, 'fdk') exportFDKFiles(f, fdkPath) myFile = f.path f.naked().modified = 0 f.close(False) OpenFont(myFile) # revert font else: myPath = GetFolder('Select folder with vfb source files') if myPath: fdkPath = setDirectory(myPath, 'fdk') allFiles = getFilePaths(myPath, '.vfb') for myFile in allFiles: f = OpenFont(myFile) print '' print 'Processing %s...' % os.path.basename(f.path) exportFDKFiles(f, fdkPath) f.naked().modified = 0 f.close(False)
def calculate_histogram(self, sender=None): print "calculate_histogram" try: font = CurrentFont() #names = self.get_glyphnames_for_histogram() histogram = {} max_width = 0 for name in self.glyphs: width = font[name].width if width > max_width: max_width = width if width in histogram: histogram[width].append(name) else: histogram[width] = [name] self.max_width = max_width self.histogram = histogram except Exception, err: print "calculate_histogram Error" print traceback.format_exc()
It saves the .glif through a GlyphSet and updates the contents.plist. This script is useful when you're working on several interpolation masters as separate vfb source files. EvB 08 """ from robofab.glifLib import GlyphSet from robofab.world import CurrentFont, CurrentGlyph, AllFonts from robofab.interface.all.dialogs import Message, GetFolder from robofab.tools.glyphNameSchemes import glyphNameToShortFileName import os f = CurrentFont() g = CurrentGlyph() f.save() todo = f.selection print "selection", todo if g is not None: todo.append(g.name) for f in AllFonts(): ufoPath = None print "f.path", f, f.path if f.path is None: # huh, in case there is a ghost font. print "skipping", f
def hasMM(nakedFont): if nakedFont[0].layers_number == 1: return False else: return True def getLayer(nakedFont, message): numberOfLayers = nakedFont[0].layers_number - 1 layers = [] while numberOfLayers >= 0: layers.append(numberOfLayers) numberOfLayers = numberOfLayers - 1 whichLayer = OneList(layers, message) return int(whichLayer) fontToChange = CurrentFont() if not hasMM(fontToChange.naked()): Message('Font needs to be MM') else: orignalMetricsFont = OpenFont(None, "Which font's sidebearings do you want?") orignalMetrics = {} tickCount = len(orignalMetricsFont) bar = ProgressBar('Getting metrics', tickCount) tick = 0 if hasMM(orignalMetricsFont.naked()): layer = getLayer(orignalMetricsFont.naked(), 'Which layer do you want?') for glyph in orignalMetricsFont: advanceWidth = int(glyph.naked().GetMetrics(layer).x) glyphWidth = int(glyph.naked().GetBoundingRect(layer).width) glyphLeft = int(glyph.naked().GetBoundingRect(layer).x)
def run(writeCoordinates=False): # Get the folder that contains the source hinting data, # and source font files: templateFolderPath = fl.GetPathName( "Select directory that contains the 'tthints' template file...") if not templateFolderPath: 'Cancel was clicked or ESC was pressed' return tthintsFilePath = os.path.join(templateFolderPath, kTTHintsFileName) # Verify that the files tthints, font.pfa/ufo and font.ttf exist # in the folder provided: if not os.path.exists(tthintsFilePath): print "ERROR: Could not find %s file." % kTTHintsFileName return # Check if any of the possible template fonts exists -- PFA, TXT, or UFO: pfaFilePath = os.path.join(templateFolderPath, kPFAFileName) txtFilePath = os.path.join(templateFolderPath, kTXTFileName) ufoFilePath = os.path.join(templateFolderPath, kUFOFileName) if os.path.exists(pfaFilePath): pass elif os.path.exists(txtFilePath): pass elif os.path.exists(ufoFilePath): pass else: print "ERROR: Could not find any of the following font files: %s, %s or %s." % ( kPFAFileName, kTXTFileName, kUFOFileName) return # Check if font.ttf exists in source folder: ttfFilePath = os.path.join(templateFolderPath, kTTFFileName) if not os.path.exists(ttfFilePath): print "ERROR: Could not find %s file." % kTTFFileName return # Get the (root) folder containingt the target font files: baseFolderPath = fl.GetPathName("Select top directory that contains the fonts to process ...") if not baseFolderPath: 'Cancel was clicked or ESC key was pressed' return startTime = time.time() # Create a list of glyphs that have been hinted so it can be # used as a filter. The rawHintingDict contains a string of raw # hinting data for each glyph: glyphList, rawHintingDict = readTTHintsFile(tthintsFilePath) folderPathsList = getFolderPaths(baseFolderPath, templateFolderPath) if len(folderPathsList): delete_temporary_template_PFA = False print "Processing template files..." fl.Open(ttfFilePath) templateTTfont = fl[fl.ifont] if not os.path.exists(pfaFilePath) and os.path.exists(txtFilePath): delete_temporary_template_PFA = True makePFAfromTXT(txtFilePath, pfaFilePath) elif not os.path.exists(pfaFilePath) and os.path.exists(ufoFilePath): delete_temporary_template_PFA = True makePFAfromUFO(ufoFilePath, pfaFilePath, glyphList) fl.Open(pfaFilePath) templateT1font = fl[fl.ifont] # Make a Robofab font of the Type1 template font. This RB font is made # by copying each glyph. There does not seem to be a simpler method # that produces reliable results -- the challenge comes from having # to close the FL font downstream. templateT1RBfont = RFont() currentT1RBfont = CurrentFont() for gName in glyphList: g = currentT1RBfont[gName] templateT1RBfont.insertGlyph(g) hintedNodeDict, indexOnlyRawHintingDict, okToProcessTargetFonts = collectTemplateIndexes( templateTTfont, templateT1font, glyphList, rawHintingDict) closeAllOpenedFonts() if okToProcessTargetFonts: processTargetFonts( folderPathsList, templateT1RBfont, hintedNodeDict, glyphList, indexOnlyRawHintingDict, writeCoordinates) else: print "Can't process target fonts because of hinting errors found in template font." if delete_temporary_template_PFA: if os.path.exists(pfaFilePath): os.remove(pfaFilePath) else: print "Could not find suitable folders to process." endTime = time.time() elapsedSeconds = endTime-startTime if (elapsedSeconds/60) < 1: print '\nCompleted in %.1f seconds.\n' % elapsedSeconds else: print '\nCompleted in %s minutes and %s seconds.\n' % ( elapsedSeconds/60, elapsedSeconds%60)
# 48 Berthold # 54 Photo typesetting and later Linotype (18*3) # 72 (18*4) # 96 Later Monotype #Always add .0 - Ej: 18.0 instead of 18 units = 36.0 #scope upper = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] lower = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] numbers = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"] punct = ["space", "period", "hyphen"] basic = punct + lower + upper + numbers f = CurrentFont() wider = 0 for n in basic: if f.has_key(n): width = f[n].width if wider < width: wider = width unit = wider / units print str(f.info.familyName) + ' ' + str(f.info.styleName) print "Fitted into a %d Units system (%d points per unit)" % (units, round(unit)) print "" for u in range(1, int(units+1)):
# >> Mark Froemberg << aka `Mark2Mark` @ GitHub # >> www.markfromberg.com << # # _NOTES: # - Take care to have the GSPen.py and objectsGS.py on first level of the glyphs # scripts folder for RoboFab to work # # _TODO: # - # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from robofab.world import CurrentFont import math f = CurrentFont() baseline = 0 descender = f.info.descender xHeight = f.info.xHeight capHeight = f.info.capHeight ascender = f.info.ascender angle = f.info.italicAngle metrics = [baseline, descender, xHeight, capHeight, ascender] g = f.newGlyph("fontmetrics", True) p = g.getPen() print dir(p) w = 600
# robothon06 # show OpenType naming records # in the fontlab API from robofab.world import CurrentFont f = CurrentFont() fn = f.naked() for r in fn.fontnames: print r.nid, r.pid, r.eid, r.lid, r.name
""" Dump the selected glyph to a .glif as part of a UFO. It saves the .glif through a GlyphSet and updates the contents.plist. Updated for UFO2 """ from robofab.glifLib import GlyphSet from robofab.world import CurrentFont, CurrentGlyph from robofab.interface.all.dialogs import Message import os f = CurrentFont() g = CurrentGlyph() ufoPath = f.path.replace(".vfb", ".ufo") if not os.path.exists(ufoPath): Message("No UFO found for this font. I'm looking for \"%s\"."%(os.path.basename(ufoPath) )) if g is not None: todo = [g.name] else: todo = f.selection if todo: Message("Exporting %s to \"%s\"."%(", ".join(todo), os.path.basename(ufoPath) )) f.writeUFO(doHints=False, doInfo=False, doKerning=False, doGroups=False, doLib=False, doFeatures=False, glyphs=todo)
#FLM: Single Glyph from a UFO """Import one glyph from a .ufo, i.e. a single .glif file. """ from robofab.world import CurrentFont from robofab.objects.objectsRF import OpenFont from robofab.interface.all.dialogs import SelectGlyph, Message flFont = CurrentFont() if flFont is None: Message("Please have a FontLab destination font ready..") else: # pick a .ufo rfFont = OpenFont() if rfFont is not None: # pick a glyph in the .ufo rfGlyph = SelectGlyph(rfFont) if rfGlyph is not None: # make a new glyph in the FL font flGlyph = flFont.newGlyph(rfGlyph.name, clear=True) # draw the glyph into the FL font pen = flGlyph.getPointPen() rfGlyph.drawPoints(pen) # set the width, unicodes and lib flGlyph.width = rfGlyph.width flGlyph.unicodes = rfGlyph.unicodes flGlyph.lib = rfGlyph.lib flGlyph.note = rfGlyph.note flGlyph.update()
""" Dump the selected glyph to a Glif as a seperate, individual file. This is not saved through a GlyphSet and any contents.plist in the same directory will not be updated. If that's what you need use DumpOneGlyphToUFO.py """ from robofab.glifLib import writeGlyphToString from robofab.world import CurrentFont, CurrentGlyph from robofab.interface.all.dialogs import PutFile from robofab.tools.glyphNameSchemes import glyphNameToShortFileName import os f = CurrentFont() g = CurrentGlyph() if g is not None: todo = [g.name] else: todo = f.selection for c in todo: g = f[c] result = True data = writeGlyphToString(g.name, g, g.drawPoints) filename = glyphNameToShortFileName(g.name, None) file = PutFile("Save this glif as:") if file is not None: path = os.path.join(os.path.dirname(file), filename)
from robofab.world import CurrentFont font = CurrentFont() for glyph in font: for contour in glyph: for point in contour.points: if point.type != "offCurve" and point.y == 689: point.y = point.y - 10 font.update() """ old = font[g] print len(old) new = font.newGlyph("dummytmp", clear=True) pen = new.getPointPen() for contour in old: pen.beginPath() for point in contour.points: if point.type != "offCurve" and point.y == 0: pen.addPoint((point.x,point.y+10),point.type) print old.name, point.x, point.y , "modifiziert!" else: pen.addPoint((point.x,point.y), point.type) pen.endPath() font.newGlyph(g, clear=True) old.appendGlyph(new) font.update()"""
class RoundToGridDialog(object): _points = True _anchors = True _sidebearings = True _mark = True _mark_color = randomColor() _gridsize = 30 _height = 235 _column_1 = 120 _title = 'round to grid' _padding_top = 10 _padding = 10 _bWidth = 80 _row_height = 30 _bSpacing = 0 def __init__(self, verbose=True): self._verbose = verbose self._width = self._column_1 + self._bWidth + (self._padding_top * 3) self.w = ModalDialog( (self._width, self._height), self._title, okCallback=self.okCallback) # grid size self.w.gridsize_label = TextBox( (self._padding, self._padding_top + (self._row_height * 0), self._column_1, self._row_height), "grid size:") self.w.gridsize_value = EditText( (self._column_1, self._padding_top + (self._row_height * 0), self._bWidth, self._row_height), self._gridsize, callback=self.gridsize_callback) # points self.w.points_checkbox = CheckBox( (self._padding, self._padding_top + (self._row_height * 1), -0, self._row_height), "points", callback=self.points_callback, value=self._points) # anchors self.w.anchors_checkbox = CheckBox( (self._padding, self._padding_top + (self._row_height * 2), -0, self._row_height), "anchors", callback=self.anchors_callback, value=self._anchors) # side-bearings self.w.sidebearings_checkbox = CheckBox( (self._padding, self._padding_top + (self._row_height * 3), -0, self._row_height), "side-bearings", callback=self.sidebearings_callback, value=self._sidebearings) # mark self.w.mark_checkbox = CheckBox( (self._padding, self._padding_top + (self._row_height * 4), -0, self._row_height), "mark", callback=self.mark_callback, value=True) # apply self.w.apply_button = Button( (self._padding, (2 * self._padding) + ((self._row_height) * 4), self._width - (2 * self._padding_top), self._row_height), 'apply', callback=self.apply_callback) # open window self.w.open() def gridsize_callback(self, sender): self._gridsize = sender.get() def points_callback(self, sender): self._points = sender.get() def anchors_callback(self, sender): self._anchors = sender.get() def sidebearings_callback(self, sender): self._sidebearings = sender.get() def mark_callback(self, sender): self._mark = sender.get() def apply_callback(self, sender): self.font = CurrentFont() if self.font is not None: gNames = getGlyphs(self.font) if len(gNames) > 0: # print info if self._verbose: print 'rounding glyphs to grid...\n' print '\tgrid size: %s' % self._gridsize print '\tpoints: %s' % self._points print '\tanchors: %s' % self._anchors print '\tside-bearings: %s' % self._sidebearings print '\tmark: %s' % self._mark print print '\t', # batch process glyphs for gName in gNames: print gName, if self._points: roundPointsToGrid(self.font[gName], (self._gridsize, self._gridsize)) if self._anchors: roundAnchorsToGrid(self.font[gName], (self._gridsize, self._gridsize)) if self._sidebearings: roundMargins(self.font[gName], self._gridsize, left=True, right=True) if self._mark: self.font[gName].mark = self._mark_color self.font[gName].update() # done print self.font.update() if self._verbose: print '\n...done.\n' # no glyphs selected else: print 'no glyph to process, please select one or more glyphs and try again.\n' # no font open else: print 'please open a font and try again.\n' def okCallback(self, sender): # print "...done.\n" pass
# robofab manual # Buildingaccents howto # usage examples from robofab.world import CurrentFont f = CurrentFont() f.newGlyph("aacute") f["aacute"].appendComponent("a") f["aacute"].appendComponent("acute", (200, 0)) f["aacute"].width = f["a"].width f.update()
# swap glyphs - Quinn Keaveney's edit of Mark Simonson from robofab.world import CurrentFont f = CurrentFont() listOne = ['zero', 'zero.pzero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] listTwo = ['zero.tnum', 'zero.tzero', 'one.tnum', 'two.tnum', 'three.tnum', 'four.tnum', 'five.tnum', 'six.tnum', 'seven.tnum', 'eight.tnum', 'nine.tnum'] listTemp = [] for i in listOne: listTemp.append(i + ".temp") l = len(listOne) def setGlyphNames(listA, listB): i = 0 while i < l: g = f[listA[i]] g.name = listB[i] g.update() g.autoUnicodes() g.update() i = i+1 if len(listOne) == len(listTwo): setGlyphNames(listOne, listTemp) # a -> a.temp setGlyphNames(listTwo, listOne) # A -> a setGlyphNames(listTemp, listTwo) # a.temp -> A f.update print 'Done! %d pairs of glyphs swapped.' % l else:
'fi': ['', 'fi', ''], 'fl': ['', 'fl', ''], 'f_f_i': ['', 'f_f_i', ''], 'f_f_l': ['', 'f_f_l', ''], 'longs_t': ['', 'longs_t', ''], 'c_h': ['', 'c_h', ''], 'c_k': ['', 'c_k', ''], 's_t': ['', 's_t', ''], 'c_t': ['', 'c_t', ''], } print "" print "Starting latin-extended-A glyph placeholder generation" font = CurrentFont() print font for glyph in glyphs: gUnicode = glyphs[glyph][0] gName = glyphs[glyph][1] if gName is not "": if gName in font: font[gName].mark = 250 print gName + " already in font" else: new = font.newGlyph(gName, False) print new
# robothon06 # use some methods to transform a glyph from robofab.world import CurrentFont font = CurrentFont() # ask a font for a glyph by name glyph = font['A'] # now you have a glyph object # make it do stuff by calling some of its methods glyph.move((100, 75)) glyph.scale((.5, 1.5)) glyph.appendGlyph(font['B']) glyph.removeOverlap() glyph.correctDirection() glyph.update()
# NOTES: # 1) Requires RoboFab to be installed. # 2) Script uses constants for vertical offsets of numerator, denominator # and subscript glyphs; you will have to adjust these for your values. # 3) Script will use the italic angle in the font to decide on the horizontal # shift required for any given vertical shift. import math # we need the Python math module to calculate the correct # horizontal shifts for vertically-moved components in italic fonts. from robofab.world import CurrentFont #import string f = CurrentFont() fontAngle=fl.font.italic_angle startCount = len(fl.font.glyphs) def splitName(): glyph.name.split('.') class Mode: # make a class for categories of glyphs being added, with different suffixes and shifts def __init__(self, glyphkind, y, x): # when initializing, get kind label and contents self.kind = glyphkind self.yShift = y self.xShift = x modes=[0,1,2] modes[0]=Mode("numr",280,math.cos(fl.font.italic_angle) * 280 * -1) modes[1]=Mode("sups",400,math.cos(fl.font.italic_angle) * 400 * -1)
# iteration through alphabetically sorted glyphnames from robofab.world import CurrentFont font = CurrentFont() print "font has %d glyphs" % len(font) # names is now a list of strings, the names of the glyphs # not the glyphs themselves! names = font.keys() # the list of names is sorted names.sort() # now we iterate through the list of names for glyphName in names: # now we ask for the glyph with glyphName print font[glyphName]
# robofab manual # Interpolate howto # Interpolating glyphs examples from robofab.world import CurrentFont f = CurrentFont() g = f.newGlyph("interpolated") g.interpolate(.5, f["a"], f["b"] # if you're in fontlab: g.update()
def expandFont(self, sender): font = CurrentFont() preserveComponents = bool(self.w.preserveComponents.get()) for glyph in font: self.expandGlyph(glyph, preserveComponents)
# robothon06 # setting data in the info object from robofab.world import CurrentFont font = CurrentFont() # naming attributes font.info.familyName = "MyFamily" print font.info.familyName font.info.styleName = "Roman" print font.info.styleName font.info.fullName = font.info.familyName + '-' + font.info.styleName print font.info.fullName # dimension attributes font.info.ascender = 600 print font.info.ascender font.info.descender = -400 print font.info.descender font.update()
# Let's talk to some of the font objects. # CurrentFont and CurrentGlyph are similar to # the RoboFog functions. They return a font # or Glyph object respectively. It will be the # front most font or the front most glyph. from robofab.world import CurrentFont, CurrentGlyph # This is a brief intro into Robofabs all singing and # dancing dialog class. It will produce simple # dialogs in almost any environment, FontLab, Python IDE, W. from robofab.interface.all.dialogs import Message # (make sure you have a font opened in FontLab) f = CurrentFont() # so now f is the name of a font object for the current font. if f == None: # let's see what dialog can do, a warning Message("You should open a font first, there's nothing to look at now!") else: # and another dialog. Message("The current font is %s"%(f.info.postscriptFullName)) # let's have a look at some of the attributes a RoboFab Font object has print "the number of glyphs:", len(f) # some of the attributes map straight to the FontLab Font class # We just straightened the camelCase here and there print "full name of this font:", f.info.postscriptFullName
#FLM: Add 1 Units to each side to current glyph # Description: # Increase current glyph sidebearings by 1 units on each side # Credits: # Pablo Impallari # http://www.impallari.com from robofab.world import CurrentFont,CurrentGlyph f = CurrentFont() g = CurrentGlyph() OldLeft = g.leftMargin OldRight = g.rightMargin g.leftMargin = OldLeft + 1 g.rightMargin = OldRight + 1 f.update()
#FLM: Draw Pseudo Ogee # Description: # Create an Pseudo Ogee shape # Credits: # Pablo Impallari1 # http://www.impallari.com # Dependencies from robofab.world import CurrentFont f = CurrentFont() # Creo un Glyphs Nuevo newGlyph = f.newGlyph('ogee', clear=True) # Creo un nuevo Pen pen = newGlyph.getPen() # Defino Medidas alto = 500 ancho = 100 # Calculo inicio_x = 100 inicio_y = 0 angulo = alto / 10 * 4.666666 curva = alto / 3.333333 # Lo mando a donde tiene que ir
def processTargetFonts(folderPathsList, templateT1RBfont, hintedNodeDict, glyphList, rawHintingDict, writeCoordinates): totalFolders = len(folderPathsList) print "%d folders found" % totalFolders fontIndex = 1 for targetFolderPath in folderPathsList: deleteTempPFA = False targetFolderName = os.path.basename(targetFolderPath) pfaFilePath = os.path.join(targetFolderPath, kPFAFileName) txtFilePath = os.path.join(targetFolderPath, kTXTFileName) ufoFilePath = os.path.join(targetFolderPath, kUFOFileName) if os.path.exists(pfaFilePath): pass elif os.path.exists(txtFilePath): deleteTempPFA = True makePFAfromTXT(txtFilePath, pfaFilePath) elif os.path.exists(ufoFilePath): deleteTempPFA = True makePFAfromUFO(ufoFilePath, pfaFilePath) else: print "ERROR: Could not find target %s/%s file. Skipping %s folder ..." % ( kPFAFileName, kTXTFileName, targetFolderName) continue ttfFilePath = os.path.join(targetFolderPath, kTTFFileName) if not os.path.exists(ttfFilePath): print "ERROR: Could not find target %s file. Skipping %s folder ..." % ( kTTFFileName, targetFolderName) continue print "\nProcessing %s ... (%d/%d)" % ( targetFolderName, fontIndex, totalFolders) fontIndex += 1 fl.Open(pfaFilePath) targetT1font = fl[fl.ifont] targetT1RBfont = CurrentFont() fl.Open(ttfFilePath) targetTTfont = fl[fl.ifont] newTTHintsFileList = ["# Glyph name\tTT hints\tGlyph color\n"] filteredGlyphList = [ gName for gName in glyphList if gName in hintedNodeDict] for gName in filteredGlyphList: gMark = None gIndex = targetT1font.FindGlyph(gName) if gIndex != -1: glyph = targetT1font[gName] else: print "ERROR: Glyph %s not found in target PS font." % gName continue # Test outline compatibility between the two glyphs # (template and target) templateT1RBglyph = templateT1RBfont[gName] targetT1RBglyph = targetT1RBfont[gName] if not templateT1RBglyph.isCompatible(targetT1RBglyph, False): # NOTE: This method doesn't catch the case in which node # indexes have rotated print "DEFINITELY NOT COMPATIBLE: %s. Skipping..." % gName continue # Verify glyph compatibility by comparing the length of segments: # Create dictionaries of the coodinates of on-curve points: ptDict1 = getGlyphOncurveCoords(templateT1RBglyph) ptDict2 = getGlyphOncurveCoords(targetT1RBglyph) # Define segments using the point coordinates from # ptDict1 and ptDict2: segmentsList = getSegmentsList(ptDict1, ptDict2) if not segmentsList: print "DEFINITELY NOT COMPATIBLE (contour mismatch): %s. Skipping ..." % gName continue # Get all pair combinations of those segments: segmentCombinationsList = list( itertools.combinations(segmentsList, 2)) # Iterate through the segment combinations and stop as soon # as an intersection between two segments is found: for combination in segmentCombinationsList: seg1, seg2 = combination[0], combination[1] if segmentsIntersect(seg1, seg2): print "POSSIBLY NOT COMPATIBLE: %s. Please check ..." % gName gMark = 25 # orange break # one incompatibility was found; # no need to report it more than once # This dictionary is indexed by the combination of the # coordinates of each node of the current glyph: ttGlyphNodeIndexDict = collectTTnodeIndexes(gName, targetTTfont) newHintsList = [] gHintsString = rawHintingDict[gName] gHintsList = gHintsString.split(";") for commandString in gHintsList: commandList = list(eval(commandString)) commandType = commandList[0] if len(commandList): if commandType in deltas: continue elif commandType in alignments: nodes = [commandList[1]] convertedNodes = getNewTTindexes( glyph, nodes, ttGlyphNodeIndexDict, hintedNodeDict) if convertedNodes is not None: writeLine = True targetNodeIndexList, targetNodeCoordsList = convertedNodes hintParamsList = [commandList[-1]] else: writeLine = False break elif commandType in links: nodes = commandList[1:3] convertedNodes = getNewTTindexes( glyph, nodes, ttGlyphNodeIndexDict, hintedNodeDict) if convertedNodes is not None: writeLine = True targetNodeIndexList, targetNodeCoordsList = convertedNodes hintParamsList = commandList[3:] else: writeLine = False break elif commandType in interpolations: nodes = commandList[1:-1] convertedNodes = getNewTTindexes( glyph, nodes, ttGlyphNodeIndexDict, hintedNodeDict) if convertedNodes is not None: writeLine = True targetNodeIndexList, targetNodeCoordsList = convertedNodes hintParamsList = [commandList[-1]] else: writeLine = False break if writeLine: if writeCoordinates: targetNodeList = targetNodeCoordsList else: targetNodeList = targetNodeIndexList newCommandList = [commandType] + targetNodeList + hintParamsList newCommandString = ','.join(map(str, newCommandList)) newHintsList.append(newCommandString.replace(" ", "")) if writeLine: newHintsLine = "%s\t%s" % (gName, ';'.join(newHintsList)) if gMark: newHintsLine = "%s\t%s" % (newHintsLine, gMark) newTTHintsFileList.append(newHintsLine + "\n") saveNewTTHintsFile(targetFolderPath, newTTHintsFileList) closeAllOpenedFonts() if deleteTempPFA: if os.path.exists(pfaFilePath): os.remove(pfaFilePath)
# Very basic setup for CS5 tagged text. Full spec is here: http://help.adobe.com/en_US/indesign/cs/taggedtext/indesign_cs5_taggedtext.pdf # Note that <cSpecialGlyph> is not in that spec, however. head = """<ASCII-MAC> <Version:7.5><FeatureSet:InDesign-Roman><ColorTable:=<Black:COLOR:CMYK:Process:0,0,0,1>> <DefineParaStyle:NormalParagraphStyle=<Nextstyle:NormalParagraphStyle>> """ paragraph = "<ParaStyle:NormalParagraphStyle>" # This is awfully long, but gets the job done glyph = "<cTypeface:%(style)s><cLigatures:0><cFont:%(family)s><cSpecialGlyph:%(glyph)s><cOTFContAlt:0><0xFFFD><cTypeface:><cLigatures:><cFont:><cSpecialGlyph:><cOTFContAlt:>" from robofab.world import CurrentFont font = CurrentFont() path = font.path.split('.')[0] + '.txt' family = font.info.openTypeNamePreferredFamilyName style = font.info.openTypeNamePreferredSubfamilyName out = head + paragraph naked = font.naked() for g in naked.glyphs: out = out + glyph % ({'family': family, 'style': style, 'glyph': g.index}) f = open(path, 'w') f.write(out) f.close()
#FLM: Compare Proportions Lowercase # Description: # Compare Lowercase Proportions to other fonts # Credits: # Pablo Impallari # http://www.impallari.com from robofab.world import OpenFont, CurrentFont from robofab.interface.all.dialogs import Message # La fuente seleccionada es la que se va a modificar myfont = CurrentFont() # Pregunta de que fuente quiero copiar las proporciones orignalFont = OpenFont(None, "Which font's Proportions do you want?") original = {} # Rango de Glyphs que voy a medir uppercase = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] # Leo las n y obtengo el Ratio original_n = orignalFont['n'].width myfont_n = myfont['n'].width # Leo la fuente de origen for item in uppercase: if myfont.has_key(item):
# Source: http://robofab.com/talks09/printBooklet.html # It is probably under the same license as Robofab, BSD # robothon 2009 # rasterise the shape in glyph "A" # and draw boxes in a new glyph named "A.silly" # from robofab.world import CurrentFont, CurrentGlyph, RGlyph f = CurrentFont() for glyph in ['a', 'b']: sourceGlyph = glyph source = f[sourceGlyph] # find out how big the shape is from the glyph.box attribute xMin, yMin, xMax, yMax = source.box # create a new glyph dest = f.newGlyph("silly") dest.width = source.width # get a pen to draw in the new glyph myPen = dest.getPen() # a function which draws a rectangle at a specified place def drawRect(pen, x, y, size=50): pen.moveTo((x-.5*size, y-.5*size)) pen.lineTo((x+.5*size, y-.5*size))
"""round all kerning values to increments of a specified value""" value = 100 from robofab.world import CurrentFont font = CurrentFont() kerning = font.kerning startCount = len(kerning) kerning.round(value) font.update() print 'finished rounding kerning by %s.' % value print 'you started with %s kerning pairs.' % startCount print 'you now have %s kerning pairs.' % len(kerning)
# 6 # 9 (DB) # 10 (JvK) # 12 (MC) # 15 (MC) # 18 (MC) # 36 (FB) #Always add .0 - Ej 18.0 instead of 18 units = 36.0 #scope lower = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] basic = lower f = CurrentFont() anchos = {} wider = 0 for n in basic: if f.has_key(n): name = f[n].name width = f[n].width anchos[name] = width if wider < width: wider = width unit = wider / units print "%d Units of %d (%.2f) points each" % (units, round(unit), unit)
# robothon06 # show encoding from robofab.world import CurrentFont f = CurrentFont() fn = f.naked() # object containing encoding records. # you can iterate through it by using an index. print fn.encoding for i in range(len(fn.encoding)): er = fn.encoding[i] print er, er.name, er.unicode
# -*- coding: utf-8 -*- from robofab.world import CurrentFont font = CurrentFont() featxt = font.features.text featxt = ' '.join(featxt.split()).split(';') for id, line in enumerate(featxt): line = line.strip() if line.startswith('@'): a = line.split(' ') groupname = a[0].replace('@','') a.remove('=') a.remove('[') a.remove(']') content = a[1:] # print groupname, '>', content print 'New group created: ' + groupname font.groups[groupname] = content
#FLM: AT Contour order + direction """correctDirection(): correct the direction of all contours in this glyphs. autoContourOrder(): automatically order the contours based on (in this order): the point count of the contours, the segment count of the contours, the x value of the center of the contours, the y value of the center of the contours and the surface of the bounding box of the contours. """ from robofab.world import CurrentFont for g in CurrentFont(): g.autoContourOrder() g.correctDirection()
#FLM: Export Current Font to UFO Format """ Export the current font to UFO format. """ from robofab.world import CurrentFont f = CurrentFont() if f.path is None: from robofab.interface.all.dialogs import PutFile path = PutFile("Please choose a name for the .ufo") if path is None: path = -1 # signal the code below the user has cancelled else: # writeUFO() will firgure out the destination .ufo path path = None if path != -1: f.writeUFO(path, doProgress=True) print 'DONE!'
#FLM: AT Copy widths to open fonts # Copy the selected widths to other fonts from robofab.world import CurrentFont, AllFonts, CurrentGlyph fonts = AllFonts() forigen = CurrentFont() sel = forigen.selection def copiaWidth(myWidth, gtarget): anchoFinal = gtarget.width anchoActual = myWidth anchoDif = anchoActual - anchoFinal anchoSide = anchoDif / 2 gtarget.leftMargin = gtarget.leftMargin + anchoSide gtarget.rightMargin = gtarget.rightMargin + anchoSide gtarget.width = myWidth print str(myWidth) + " > " + str(gtarget.width) for f in fonts: for gname in sel: if gname in f: destino = f[gname] origen = forigen[gname] print f[gname] destino.mark = origen.mark copiaWidth(origen.width, destino) f.update() print sel
# # RoboFab font objects have several objects associated with them # kerning, info, groups, etc. Let's talk about groups. Groups are, # well groups of glyph names. These can be useful for lots of things # like kerning and OpenType features. The number of uses for # groups is only limited by your imagination. Enough of this # silly pep talk. Let's check it out. from robofab.world import CurrentFont # gString has lots of glyph lists, these two will be useful for this demo from robofab.gString import uppercase_plain, lowercase_plain # (you will need t have a font open in FontLab for this demo) font = CurrentFont() # First off, let's gather up some glyph names. # gString's uppercase_plain and lowercase_plain # lists will do for now. Let's go through these lists # and see if they contain any glyphs that are in this font. uppercase = [] lowercase = [] for glyphName in uppercase_plain: if font.has_key(glyphName): uppercase.append(glyphName) for glyphName in lowercase_plain: if font.has_key(glyphName): lowercase.append(glyphName) uppercase.sort() lowercase.sort()
# robothon06 from robofab.world import CurrentFont # We need to import a class with a different # implementation for the glyph object. # It looks a bit odd, but this is how it is done from robofab.objects.objectsRF import RGlyph as _RGlyph f = CurrentFont() # pick two compatible glyphs as masters m1 = f["A"] m2 = f["B"] # make a new glyph object from this other glyph class g = _RGlyph() # interpolation factor which is bound to make floats oddFactor = 0.2382345 # go! g.interpolate(oddFactor, m1, m2) # let's have a look at the raw results for contour in g: for pt in contour.points: print "float", pt.x, pt.y # a glyph can round itself off: g.round()
#FLM: Copy Font Sidebearing # (c) Ben Kiel # # Copys one font's sidebearing values to another font #Imports from robofab.world import OpenFont, CurrentFont from robofab.interface.all.dialogs import Message fontToChange = CurrentFont() orignalMetricsFont = OpenFont(None, "Which font's sidebearings do you want?") orignalMetrics = {} for glyph in orignalMetricsFont: orignalMetrics[glyph.name] = [glyph.leftMargin, glyph.rightMargin] orignalMetricsFont.close() for name, metrics in orignalMetrics.iteritems(): if fontToChange.has_key(name): fontToChange[name].leftMargin = metrics[0] fontToChange[name].rightMargin = metrics[1] fontToChange.update() Message('Done changing sidebearings')