def simplepolateFonts(registerobject, font): # Ask user how many children to create, default is 5 amount = 5 s = fontforge.askString("Simple Font Interpolation", "How many children?", str(amount)) try: amount = int(s) except: fontforge.postError("Bad value", "Expected whole number") # figure out the interpolation amount floats based on how many children the user requested interpolationamount = [0.0] calcamount = amount + 1 x = 1.0 / calcamount for y in range(1, calcamount): interpolationamount.append(x * y) interpolationamount.append(1.0) # TODO: This should ask the user to choose which is source1 and source2 # get the souce fonts from the 2 currently open (check for only 2 open is in shouldWeAppear()) fonts = fontforge.fonts() source1 = fonts[0] source2 = fonts[1] # get a name for the children - font-name-generator.py supplies gibberish() so if we have that available, lets use it name = source1.familyname + " Simp" newName = fontforge.askString("Simplepolate Fonts", "Base family name?", str(name)) # create all the children for x in range(amount + 2): # TODO I thought this would work but it doesn't # newFont = source1.interpolateFonts(interpolationamount[x],source2.path) # TODO and I thought this would work because it does on its own, but if its even just repeated twice right next to each other, it doesn't work!! :( source1.interpolateFonts(interpolationamount[x], source2.path) newFontName = newName + ' ' + str(int( interpolationamount[x] * 100)).zfill(3) newFont = fontforge.activeFont() # Set PostScript Style Name (FamilyName-Style) newFont.weight = "Regular" newFont.fontname = newFontName.replace(' ', '') + '-' + newFont.weight # Set PostScript Family Name (Family Name) newFont.familyname = newFontName # Set PostScript Full Name (Family Name Style) newFont.fullname = newFontName + ' ' + font.weight # let folks know what we did message = "Simplepolated %s: %s%%/%s%% %s/%s" % ( newFont.fullname, int(100 - interpolationamount[x] * 100), int(interpolationamount[x] * 100), source1.fontname, source2.fontname) note(message)
def YOffset(percent, afont): '''Adjust the Y position.''' em = afont.ascent + afont.descent / 2 if not percent: ret = fontforge.askString('Offset Percent?', 'Percent of Offset?', '64') if not ret: return try: percent = float(ret) / 100 if percent < -1.5 or percent > 1.5: raise ValueError except ValueError: fontforge.postError('Wrong Percent!', "Need a value abs(x) <= 150.") return if percent == 0: # Do Nothing. return tavg, bavg = get_avg_topbtm(afont) if percent > 0: deltay = (afont.ascent - tavg) * percent else: deltay = (afont.descent - bavg) * percent matrix = psMat.translate(0, deltay) for glyph in afont.selection.byGlyphs: glyph.transform(matrix)
def YOffset(percent, afont): '''Adjust the Y position.''' em = afont.ascent + afont.descent/2 if not percent: ret = fontforge.askString('Offset Percent?', 'Percent of Offset?', '64' ) if not ret: return try: percent = float(ret)/100 if percent < -1.5 or percent > 1.5: raise ValueError except ValueError: fontforge.postError('Wrong Percent!', "Need a value abs(x) <= 150.") return if percent == 0: # Do Nothing. return tavg, bavg = get_avg_topbtm(afont) if percent > 0: deltay = (afont.ascent - tavg)*percent else: deltay = (afont.descent - bavg)*percent matrix = psMat.translate(0, deltay) for glyph in afont.selection.byGlyphs: glyph.transform(matrix)
def simplepolateFonts(registerobject, font): # Ask user how many children to create, default is 5 amount = 5 s = fontforge.askString("Simple Font Interpolation", "How many children?", str(amount)) try: amount = int(s) except: fontforge.postError("Bad value", "Expected whole number") # figure out the interpolation amount floats based on how many children the user requested interpolationamount = [0.0] calcamount = amount +1 x = 1.0 / calcamount for y in range(1, calcamount): interpolationamount.append(x*y) interpolationamount.append(1.0) # TODO: This should ask the user to choose which is source1 and source2 # get the souce fonts from the 2 currently open (check for only 2 open is in shouldWeAppear()) fonts = fontforge.fonts() source1 = fonts[0] source2 = fonts[1] # get a name for the children - font-name-generator.py supplies gibberish() so if we have that available, lets use it name = source1.familyname + " Simp" newName = fontforge.askString("Simplepolate Fonts", "Base family name?", str(name)) # create all the children for x in range(amount+2): # TODO I thought this would work but it doesn't # newFont = source1.interpolateFonts(interpolationamount[x],source2.path) # TODO and I thought this would work because it does on its own, but if its even just repeated twice right next to each other, it doesn't work!! :( source1.interpolateFonts(interpolationamount[x],source2.path) newFontName = newName + ' ' + str(int(interpolationamount[x]*100)).zfill(3) newFont = fontforge.activeFont() # Set PostScript Style Name (FamilyName-Style) newFont.weight = "Regular" newFont.fontname = newFontName.replace(' ', '') + '-' + newFont.weight # Set PostScript Family Name (Family Name) newFont.familyname = newFontName # Set PostScript Full Name (Family Name Style) newFont.fullname = newFontName + ' ' + font.weight # let folks know what we did message = "Simplepolated %s: %s%%/%s%% %s/%s" % (newFont.fullname, int(100-interpolationamount[x]*100), int(interpolationamount[x]*100), source1.fontname, source2.fontname) note(message)
def simplepolate(registerobject, font): # Ask user how many children to create, default is 5 amount = 5 s = fontforge.askString("Simple Glyph Interpolation", "How many children?", str(amount)) try: amount = int(s) except: fontforge.postError("Bad value", "Expected whole number") # figure out the interpolation amount floats based on how many children the user requested interpolationamount = [0.0] calcamount = amount +1 x = 1.0 / calcamount for y in range(1, calcamount): interpolationamount.append(x*y) interpolationamount.append(1.0) # get the souce glyphs from the selection -- this should be simpler... glyphs = [] for g in font.selection.byGlyphs: glyphs.append(g) source1 = glyphs[0] source2 = glyphs[1] # get a name for the children - font-name-generator.py supplies gibberish() so if we have that available, lets use it if gibberish: name = gibberish(1) else: name = "simplepolation" name = fontforge.askString("Simple Glyph Interpolation", "Children names?", str(name)) # create all the children for x in range(amount+2): glyphname = str(name) + '.'+ str(x+1) g = font.createChar(-1, glyphname) g.preserveLayerAsUndo(1) # interpolate the top layer g.layers[1] = source1.layers[1].interpolateNewLayer(source2.layers[1], interpolationamount[x]) # interpolate the width g.width = source1.width + (source2.width - source1.width)*interpolationamount[x] # interpolate the vwidth g.vwidth = source1.vwidth + (source2.vwidth - source1.vwidth)*interpolationamount[x] # let folks know what we did message = "Simplepolator created '%s' that is %s%% '%s' and %s%% '%s'" % (glyphname, int(100-interpolationamount[x]*100), source1.glyphname, int(interpolationamount[x]*100), source2.glyphname) note(message)
def geMaster(myFont): myFont.save() mastLayer1 = 'Fore' s1 = fontforge.askString("Export layers to masters", "Name of the Light Master layer ?", str(mastLayer1)) mastLayer1 = s1 mastLayer2 = 'Back' s2 = fontforge.askString("Export layers to masters", "Name of the ExtraBold Master layer ?", str(mastLayer2)) mastLayer2 = s2 fontName = myFont.fontname fontforge.logWarning("Saved master file") myFont.generate(fontName + '_1.otf', layer=mastLayer1) fontforge.logWarning("Generated Light from Foreground") myFont.generate(fontName + '_0.otf', layer=mastLayer1) fontforge.logWarning("Generated ExBld from mastLayer1")
def ScaleToSquare(percent, afont): '''Scale a font to nearly fit a square.''' if not percent: ret = fontforge.askString('Scale Percent?', 'Percent of Scale?', '20') if not ret: return try: percent = float(ret) / 100 if percent <= 0 or percent > 1: raise ValueError except ValueError: fontforge.postError('Wrong Percent!', "Need a value <= 100.") return for glyph in afont.selection.byGlyphs: fit_glyph_box(glyph, percent)
def ScaleToSquare(percent, afont): '''Scale a font to nearly fit a square.''' if not percent: ret = fontforge.askString('Scale Percent?', 'Percent of Scale?', '20' ) if not ret: return try: percent = float(ret)/100 if percent <= 0 or percent > 1: raise ValueError except ValueError: fontforge.postError('Wrong Percent!', "Need a value <= 100.") return for glyph in afont.selection.byGlyphs: fit_glyph_box(glyph, percent)
def BoundToSquare(percent, afont): '''Scale a font to nearly fit the average width.''' em = afont.ascent + afont.descent if not percent: ret = fontforge.askString('Scale Percent?', 'Percent of Scale?', '36') if not ret: return try: percent = float(ret) / 100 if percent <= 0 or percent > 1: raise ValueError except ValueError: fontforge.postError('Wrong Percent!', "Need a value <= 100.") return wavg, havg = get_avg_size(afont) for glyph in afont.selection.byGlyphs: box_fit_square(glyph, em, percent, wavg, havg)
def viewPoints(junk, glyph): pointdict = getDict("pointdict", glyph) answ = ff.askString( "View parametrized points", printTbl( "Coordinate : value", pointdict, "Supported commands:\n[i]nsert [r]emove removeall [u]pdate [q]uit") ) if answ == "insert" or answ == "i": pname = ff.askString("New parametrization", "Name of coordinate to be parameterized:") if pname: if pname in pointdict: ff.postError( "Insertion error", "A coordinate with this name already exists. Choose a different name or update instead" ) else: pval = ff.askString("New parametrization", "Coordinate value:") if pval: pointdict[pname] = pval elif answ == "remove" or answ == "r": toremove = ff.askString( "Remove point parametrization", "Name of coordinate to be deparameterized (the point will not be removed):" ) if toremove: del pointdict[toremove] elif answ == "removeall": pointdict = {} elif answ == "update" or answ == "u": pname = ff.askString("Update point parametrization", "Name of coordinate to update:") if pname: if not pname in pointdict: ff.postError( "Update error", "A coordinate with this name does not exist. Choose an existing coordinate or parametrize existing points." ) else: pval = ff.askString("Update coordinate", "New coordinate value:") if pval: pointdict[pname] = pval elif answ == "quit" or answ == "q" or not answ: return glyph.persistent['pointdict'] = pointdict updatePoints(glyph) viewPoints(junk, glyph)
def BoundToSquare(percent, afont): '''Scale a font to nearly fit the average width.''' em = afont.ascent + afont.descent if not percent: ret = fontforge.askString('Scale Percent?', 'Percent of Scale?', '36' ) if not ret: return try: percent = float(ret)/100 if percent <= 0 or percent > 1: raise ValueError except ValueError: fontforge.postError('Wrong Percent!', "Need a value <= 100.") return wavg, havg = get_avg_size(afont) for glyph in afont.selection.byGlyphs: box_fit_square(glyph, em, percent, wavg, havg)
def parametrizePoints(junk, glyph): pointdict = getDict("pointdict", glyph) name = ff.askString("Parametrize points", "Name points (do not change afterwards):") if not name: # canceled by user return newx = ff.askString("Parametrize points", "Set x coordinate (empty=skip):") newy = ff.askString("Parametrize points", "Set y coordinate (empty=skip):") newri = ff.askString("Parametrize points", "Set incoming radius (empty=skip):") newphii = ff.askString("Parametrize points", "Set incoming angle (degrees, empty=skip):") newro = ff.askString("Parametrize points", "Set outgoing radius (empty=skip):") newphio = ff.askString("Parametrize points", "Set outgoing angle (degrees, empty=skip):") glyph.preserveLayerAsUndo() # to make renaming undoable layercopy = glyph.layers[ff.activeLayer()] for contour in layercopy: for idx, point in enumerate(contour): if point.selected: point.name = name if idx > 0 and not contour[idx - 1].on_curve: contour[idx - 1].name = name if idx < len(contour) - 1 and not contour[idx + 1].on_curve: contour[idx + 1].name = name if newx: pointdict[name + "_x"] = newx if newy: pointdict[name + "_y"] = newy if newri: pointdict[name + "_ri"] = newri if newphii: pointdict[name + "_phii"] = newphii if newro: pointdict[name + "_ro"] = newro if newphio: pointdict[name + "_phio"] = newphio glyph.layers[ff.activeLayer()] = layercopy glyph.persistent['pointdict'] = pointdict updatePoints(glyph)
def viewParameters(junk, fontOrGlyph): font = getFont(fontOrGlyph) paramdict = getDict("paramdict", font) answ = ff.askString( "View parameters", printTbl( "Parameter : value", paramdict, "Supported commands:\n[i]nsert [r]emove removeall [u]pdate [q]uit") ) if answ == "insert" or answ == "i": pname = ff.askString("New parameter", "Parameter name:") if pname: if pname in paramdict: ff.postError( "Insertion error", "A parameter with this name already exists. Choose a different name or update instead" ) else: pval = ff.askString("New parameter", "Parameter value:") if pval: paramdict[pname] = pval elif answ == "remove" or answ == "r": toremove = ff.askString("Remove parameter", "Name of parameter to remove:") if toremove: del paramdict[toremove] elif answ == "removeall": paramdict = {} elif answ == "update" or answ == "u": pname = ff.askString("Update parameter", "Parameter name:") if pname: if not pname in paramdict: ff.postError( "Update error", "A parameter with this name does not exist. Choose an existing parameter or insert instead" ) else: pval = ff.askString("Update parameter", "Parameter value:") if pval: paramdict[pname] = pval elif answ == "quit" or answ == "q" or not answ: return font.persistent['paramdict'] = paramdict updateAllGlyphs(junk, font) viewParameters(junk, font)
def ScaleToEm(percent, afont): '''Scale a font to fit 5% less than the em.''' #em = afont.ascent + afont.descent em = afont.ascent + afont.descent / 2 center = (afont.ascent - afont.descent / 2) / 2 lbearing = int(em * 0.05) if not percent: ret = fontforge.askString('Scale Percent?', 'Percent of Line Height (em)?', '95') if not ret: return try: percent = float(ret) / 100 if percent <= 0 or percent > 1.5: raise ValueError except ValueError: fontforge.postError('Wrong Percent!', "Need a value <= 150.") return wavg, havg = get_avg_size(afont) for glyph in afont.selection.byGlyphs: #fit_glyph(glyph, em, percent) fit_glyph_plus(glyph, em, percent, wavg, havg) #center_glyph(glyph, center, lbearing) # Maybe not move glyph? center_glyph_height(glyph, center)
def ScaleToEm(percent, afont): '''Scale a font to fit 5% less than the em.''' #em = afont.ascent + afont.descent em = afont.ascent + afont.descent/2 center = (afont.ascent - afont.descent/2)/2 lbearing = int(em*0.05) if not percent: ret = fontforge.askString('Scale Percent?', 'Percent of Line Height (em)?', '95' ) if not ret: return try: percent = float(ret)/100 if percent <= 0 or percent > 1.5: raise ValueError except ValueError: fontforge.postError('Wrong Percent!', "Need a value <= 150.") return wavg, havg = get_avg_size(afont) for glyph in afont.selection.byGlyphs: #fit_glyph(glyph, em, percent) fit_glyph_plus(glyph, em, percent, wavg, havg) #center_glyph(glyph, center, lbearing) # Maybe not move glyph? center_glyph_height(glyph, center)
def newBackgroundLayerDialog(junk,glyph): layerName = fontforge.askString("New Background Layer","Layer name?",myDate) newBackgroundLayer(layerName)
def simplepolate(registerobject, font): # Ask user how many children to create, default is 5 amount = 5 s = fontforge.askString("Simplepolate", "How many children? (1-8)", str(amount)) try: amount = int(s) except: fontforge.postError("Bad value", "Expected whole number") return if 1 <= amount >= 9: fontforge.postError("Bad value", "1 to 9, please") return # figure out the interpolation amount floats based on how many children the user requested interpolationamount = [] calcamount = amount +1 x = 1.0 / calcamount for y in range(1, calcamount): interpolationamount.append(x*y) interpolationamount.append(1.0) # get the souce glyphs from the selection -- this would be simpler in robofab :) glyphs = [] for g in font.selection.byGlyphs: glyphs.append(g) source1 = glyphs[0] source2 = glyphs[1] name = source1.glyphname print "Adding %s Style Sets to %s" % (amount, name) # create all the children for x in range(amount+1): # create the style set name ss = 'ss'+ str(x+1).zfill(2) glyphname = str(name) + '.' + ss # create a char slot g = font.createChar(-1, glyphname) # make this undoable g.preserveLayerAsUndo(1) # interpolate the top layer g.layers[1] = source1.layers[1].interpolateNewLayer(source2.layers[1], interpolationamount[x]) # interpolate the width g.width = source1.width + (source2.width - source1.width)*interpolationamount[x] # interpolate the vwidth g.vwidth = source1.vwidth + (source2.vwidth - source1.vwidth)*interpolationamount[x] # add lookup for each ss, eg ss01, if it doesn't already exist lookup = str(ss) if lookup not in font.gsub_lookups: flags = ("","") featureScriptLangTuple = ((lookup,(("latn",("dflt")),)),) # featureScriptLangTuple = (('ss07', (('latn', 'dflt'),)),) font.addLookup(lookup, "gsub_single", (), featureScriptLangTuple) # check for existing subtables if len(font.getLookupSubtables(lookup)) == 0: subtable = lookup + '-0' font.addLookupSubtable(lookup, subtable) else: subtable = font.getLookupSubtables(lookup)[0] # add the substitution source1.addPosSub(subtable,glyphname) # merge the subtables (thanks to khaled hosney for this!) for lookup in font.gsub_lookups: while 1 < len(font.getLookupSubtables(lookup)): font.mergeLookupSubtables(font.getLookupSubtables(lookup)[1], font.getLookupSubtables(lookup)[0]) # let folks know what we did message = " Created %s %s%%/%s%% %s/%s (%s:%s)" % (glyphname, int(100-interpolationamount[x]*100), int(interpolationamount[x]*100), source1.glyphname, source2.glyphname, lookup, subtable) note(message)
def simplepolate(registerobject, font): # Ask user how many children to create, default is 5 amount = 5 s = fontforge.askString("Simplepolate", "How many children? (1-8)", str(amount)) try: amount = int(s) except: fontforge.postError("Bad value", "Expected whole number") return if 1 <= amount >= 9: fontforge.postError("Bad value", "1 to 9, please") return # figure out the interpolation amount floats based on how many children the user requested interpolationamount = [] calcamount = amount + 1 x = 1.0 / calcamount for y in range(1, calcamount): interpolationamount.append(x * y) interpolationamount.append(1.0) # get the souce glyphs from the selection -- this would be simpler in robofab :) glyphs = [] for g in font.selection.byGlyphs: glyphs.append(g) source1 = glyphs[0] source2 = glyphs[1] name = source1.glyphname print "Adding %s Style Sets to %s" % (amount, name) # create all the children for x in range(amount + 1): # create the style set name ss = 'ss' + str(x + 1).zfill(2) glyphname = str(name) + '.' + ss # create a char slot g = font.createChar(-1, glyphname) # make this undoable g.preserveLayerAsUndo(1) # interpolate the top layer g.layers[1] = source1.layers[1].interpolateNewLayer( source2.layers[1], interpolationamount[x]) # interpolate the width g.width = source1.width + (source2.width - source1.width) * interpolationamount[x] # interpolate the vwidth g.vwidth = source1.vwidth + (source2.vwidth - source1.vwidth) * interpolationamount[x] # add lookup for each ss, eg ss01, if it doesn't already exist lookup = str(ss) if lookup not in font.gsub_lookups: flags = ("", "") featureScriptLangTuple = ((lookup, (("latn", ("dflt")), )), ) # featureScriptLangTuple = (('ss07', (('latn', 'dflt'),)),) font.addLookup(lookup, "gsub_single", (), featureScriptLangTuple) # check for existing subtables if len(font.getLookupSubtables(lookup)) == 0: subtable = lookup + '-0' font.addLookupSubtable(lookup, subtable) else: subtable = font.getLookupSubtables(lookup)[0] # add the substitution source1.addPosSub(subtable, glyphname) # merge the subtables (thanks to khaled hosney for this!) for lookup in font.gsub_lookups: while 1 < len(font.getLookupSubtables(lookup)): font.mergeLookupSubtables( font.getLookupSubtables(lookup)[1], font.getLookupSubtables(lookup)[0]) # let folks know what we did message = " Created %s %s%%/%s%% %s/%s (%s:%s)" % ( glyphname, int(100 - interpolationamount[x] * 100), int(interpolationamount[x] * 100), source1.glyphname, source2.glyphname, lookup, subtable) note(message)
def ask_user_fit (): value = fontforge.askString("Fit Curve", """Enter a number (0 = curve becomes a line, 100 = control points converge)""") if value == None: return value else: return float(value)/100.0