Source code for hTools2.modules.fontutils

# [h] hTools2.modules.fontutils

"""A collection of handy functions for working with fonts."""

# imports

import os

from random import randint

try:
    from mojo.roboFont import CurrentGlyph, CurrentFont, NewFont
    from lib.tools.defaults import getDefault

except:
    from robofab.world import CurrentGlyph, CurrentFont, NewFont

from hTools2.modules.glyphutils import round_points, round_width
from hTools2.modules.color import *

#--------
# glyphs
#--------

[docs]def get_glyphs(font): # current_glyph=True, font_selection=True, """Return current glyph selection in the font as glyph names or ``RGlyph`` objects.""" # get glyphs current_glyph = CurrentGlyph() font_selection = font.selection # get RoboFont's window mode single_window = [ False, True ][getDefault("singleWindowMode")] # handle multi-window mode glyphs = [] if not single_window: if current_glyph is not None: glyphs += [current_glyph.name] else: glyphs += font_selection # multi-window: return else: if current_glyph is not None: glyphs += [current_glyph.name] glyphs += font_selection else: glyphs += font_selection # done return list(set(glyphs))
[docs]def parse_glyphs_groups(names, groups): """Parse a ``gstring`` and a groups dict into a list of glyph names.""" glyph_names = [] for name in names: # group names if name[0] == '@': group_name = name[1:] if groups.has_key(group_name): glyph_names += groups[group_name] else: print 'project does not have a group called %s.\n' % group_name # glyph names else: glyph_names.append(name) return glyph_names
[docs]def rename_glyph(font, old_name, new_name, overwrite=True, mark=True, verbose=True): """Rename a glyph in a font from ``old_name`` to ``new_name``.""" if font.has_key(old_name): g = font[old_name] # if new name already exists in font if font.has_key(new_name): # option [1] (default): overwrite if overwrite is True: if verbose: print '\trenaming "%s" to "%s" (overwriting existing glyph)...' % (old_name, new_name) font.removeGlyph(new_name) g.name = new_name if mark: g.mark = named_colors['orange'] g.update() # option [2]: skip, do not overwrite else: if verbose: print '\tskipping "%s", "%s" already exists in font.' % (old_name, new_name) if mark: g.mark = named_colors['red'] g.update() # if new name not already in font, simply rename glyph else: if verbose: print '\trenaming "%s" to "%s"...' % (old_name, new_name) g.name = new_name if mark: g.mark = named_colors['green'] g.update() # done glyph else: if verbose: print '\tskipping "%s", glyph does not exist in font.' % old_name # done font font.update()
[docs]def rename_glyphs_from_list(font, names_list, overwrite=True, mark=True, verbose=True): if verbose: print 'renaming glyphs...\n' for pair in names_list: old_name, new_name = pair rename_glyph(font, old_name, new_name, overwrite, mark, verbose) if verbose: print print '...done.\n'
[docs]def mark_composed_glyphs(font, color='Orange', alpha=.35): """Mark all composed glyphs in the font.""" R, G, B = x11_colors[color] mark_color = convert_to_1(R, G, B) mark_color += (alpha,) for glyph in font: if len(glyph.components) > 0: glyph.mark = mark_color glyph.update() font.update() #-------- # groups #--------
[docs]def delete_groups(font): """Delete all groups in the font.""" for group in font.groups.keys(): del font.groups[group] font.update()
[docs]def get_spacing_groups(font): """Return a dictionary containing the ``left`` and ``right`` spacing groups in the font.""" _groups = {} _groups['left'] = {} _groups['right'] = {} for _group in font.groups.keys(): if _group[:1] == '_': if _group[1:5] == 'left': _groups['left'][_group] = font.groups[_group] if _group[1:6] == 'right': _groups['right'][_group] = font.groups[_group] return _groups
[docs]def get_full_name(font): """Return the full name of the font, usually family name + style name.""" full_name = '%s %s' % (font.info.familyName, font.info.styleName) return full_name
[docs]def full_name(family, style): """Build the full name of the font from ``family`` and ``style`` names. Names are separated by a space. If the ``style`` is Regular, use only the ``family`` name. """ if style == 'Regular': full_name = family else: full_name = family + ' ' + style return full_name
[docs]def font_name(family, style): """Same as ``full_name()``, but ``family`` and ``style`` names are separated by a hyphen instead of space.""" if style == 'Regular': font_name = family else: font_name = family + '-' + style return font_name
[docs]def set_unique_ps_id(font): """Set random unique PostScript ID.""" a, b, c, d, e, f = randint(0,9), randint(0,9), randint(0,9), randint(0,9), randint(0,9), randint(0,9) _psID = "%s%s%s%s%s%s" % ( a, b, c, d, e, f ) font.info.postscriptUniqueID = int(_psID)
[docs]def set_foundry_info(font, fontInfoDict): """Set foundry info from data in dict.""" font.info.year = fontInfoDict['year'] font.info.openTypeNameDesigner = fontInfoDict['designer'] font.info.openTypeNameDesignerURL = fontInfoDict['designerURL'] font.info.openTypeNameManufacturerURL = fontInfoDict['vendorURL'] font.info.openTypeNameManufacturer = fontInfoDict['vendor'] font.info.openTypeOS2VendorID = fontInfoDict['vendor'] font.info.copyright = fontInfoDict['copyright'] font.info.trademark = fontInfoDict['trademark'] font.info.openTypeNameLicense = fontInfoDict['license'] font.info.openTypeNameLicenseURL = fontInfoDict['licenseURL'] font.info.openTypeNameDescription = fontInfoDict['notice'] font.info.versionMajor = fontInfoDict['versionMajor'] font.info.versionMinor = fontInfoDict['versionMinor'] font.info.openTypeNameUniqueID = "%s : %s : %s" % (fontInfoDict['foundry'], font.info.postscriptFullName, font.info.year) set_unique_ps_id(font) f.update()
[docs]def set_font_names(f, family_name, style_name): """Set font names from ``family_name`` and ``style_name``.""" # family name f.info.familyName = family_name f.info.openTypeNamePreferredFamilyName = family_name # style name f.info.styleName = style_name f.infoopenTypeNamePreferredSubfamilyName = style_name # fallback name f.info.styleMapFamilyName = '%s%s' % (family_name, style_name) f.info.styleMapStyleName = "regular" # composed names f.info.postscriptFontName = '%s-%s' % (family_name, style_name) f.info.postscriptFullName = '%s %s' % (family_name, style_name) f.info.macintoshFONDName = '%s-%s' % (family_name, style_name) set_unique_ps_id(f) # done f.update() #------------ # guidelines #------------
[docs]def clear_guides(font): for guide in font.guides: font.removeGuide(guide)
[docs]def create_guides(font, guides_dict): for guide_name in guides_list: font.addGuide((0, 0), 0, name=guide_name) font.update()
[docs]def decompose(font): """Decompose all composed glyph in the font.""" for glyph in font: glyph.decompose()
[docs]def auto_contour_order(font): """Automatically set contour order for all glyphs in the font.""" for glyph in font: glyph.correctDirection()
[docs]def auto_contour_direction(font): """Automatically set contour directions for all glyphs in the font.""" for glyph in font: glyph.correctDirection()
[docs]def auto_order_direction(font): """Automatically set contour order and direction for all glyphs in the font, in one go.""" for glyph in font: glyph.autoContourOrder() glyph.correctDirection()
[docs]def add_extremes(font): """Add extreme points to all glyphs in the font, if they are missing.""" for glyph in font: glyph.extremePoints()
[docs]def remove_overlap(font): """Remove overlaps in all glyphs of the font.""" for glyph in font: glyph.removeOverlap()
[docs]def align_to_grid(font, (sizeX, sizeY)): """Align all points of all glyphs in the font to a grid with size ``(sizeX,sizeY)``.""" for glyph in font: round_points(glyph, (sizeX, sizeY)) glyph.update() font.update()
[docs]def scale_glyphs(f, (factor_x, factor_y)): """Scale all glyphs in the font by the given ``(x,y)`` factor.""" for g in f: if len(g.components) == 0: leftMargin, rightMargin = g.leftMargin, g.rightMargin g.scale((factor_x, factor_y)) g.leftMargin = leftMargin * factor_x g.rightMargin = rightMargin * factor_x g.update() f.update()
[docs]def move_glyphs(f, (delta_x, delta_y)): """Move all glyphs in the font by the given ``(x,y)`` distance.""" for g in f: g.move((delta_x, delta_y)) g.update() f.update()
[docs]def round_to_grid(font, gridsize, glyphs=None): if glyphs is None: glyphs = font.keys() for glyph_name in glyphs: round_points(font[glyph_name], (gridsize, gridsize)) round_width(font[glyph_name], gridsize) font.update() #------ # misc #------
[docs]def temp_font(): """Return a temporary font for importing single ``.glyfs``.""" if CurrentFont() is None: t = NewFont() else: t = CurrentFont() return t