"""Heuristic attempting to extract descriptions from font names This should only be used as a backup in case there is no proper available querying mechanism (i.e. fonttools), and even then, we really would rather avoid using this extremely fragile mechanism. Basically what happens is that a name compression function is run over the font name, as seen in the Windows Registry, producing a base name and a set of modifiers, with the modifiers being the weight (as a string) and a flag indicating whether the font appears to be italicised. XXX This is English-specific and entirely dependent on the naming conventions commonly seen when naming fonts, so there will be a considerable number of cases where the resulting name and flags will be incorrect. """ WEIGHTS = [ 'demibold', 'extrabold', 'semibold', 'ultrabold', 'bold', 'ultralight', 'extralight', 'light', 'heavy', 'medium', 'thin', ] IGNORE_MODIFIERS = [ "unicode", "regular", "normal", "bt", "let", ## "mt", 'itc', "(truetype)", 'ft', 'win95bt', 'plain:1.0', 'plain', 'plain:', ] WEIGHT_SYNONYMS = [ ('lt', 'light'), ('lite', 'light'), ('bolditalic','bold'), ('demi', 'demibold'), ('semi', 'semibold'), ] WEIGHT_MODIFIERS = [ 'extra', 'ultra' ] ITALIC_INDICATORS = [ 'italic', 'ital','itali', 'it', 'bolditalic', ] def interpretModifiers( name ): """Heuristic attempt to get weight and italic data from font-name return base_font_name, (weight, italic) """ name = name.replace('_',' ').replace('-',' ').lower().split() weight = "normal" for w in WEIGHTS: if w in name: weight = w while w in name: name.remove( w ) break for w,syn in WEIGHT_SYNONYMS: if w in name: weight = syn while w in name: name.remove( w ) if weight in ('bold','light'): # "extra bold", "extra light", etceteras for w in WEIGHT_MODIFIERS: if w in name: weight = w+weight while w in name: name.remove( w ) break # XXX should look for "extra" and "ultra" w/out bold/light, # but that that point we're basically just shooting blind # as to which it is... for i in ITALIC_INDICATORS: if i in name: italic = 1 while i in name: name.remove( i ) break else: italic = 0 for i in IGNORE_MODIFIERS: while i in name: name.remove( i ) name = " ".join( name ) if not name.strip(): # MT Extra raise ValueError( "name reduced to null by name compression" ) return None,(None,None) return name, (weight, italic) def add( name, file ): """Add a font with name and file to this module's registry""" name, style = interpretModifiers( name ) if name is not None: SYSTEM_FONTS.setdefault(name, {})[style] = file return name, style def get( name, style=None ): """Get a font by name and optional style Style defaults to ("normal", 0) """ name, tstyle = interpretModifiers( name ) if tstyle != style and style is None: style = tstyle set = SYSTEM_FONTS.get( name ) if set: if set.has_key( style ): return set[style] # try match on italics for key, value in set.items(): if key[1] == style[1]: return value # try match on weight for key, value in set.items(): if key[0] == style[0]: return value # well, there's at least one font here, use it... for key, value in set.items(): return value return None