graphics: Add kerning for text generator.

Adjust character positions so that some pairs of characters can fit
more closely together.
This commit is contained in:
Simon Howard 2013-12-01 23:20:15 -05:00
parent 0948019b1a
commit b37baf5abb
2 changed files with 69 additions and 8 deletions

View file

@ -33,6 +33,41 @@
# that are generated, and the text to show in each one.
#
# Adjustments for character position based on character pairs. Some
# pairs of characters can fit more snugly together, which looks more
# visually appealing. This is highly dependent on the font graphics,
# and if the font is changed this probably needs to be redone.
FONT_KERNING_RULES = {
# Right character fits under left character:
r'p[aj\.]': -3,
r'P[a\.]': -4,
r'[PVW][AJj\.]': -4,
r't[ajJ\.]': -4,
r'f[aj\.]': -2,
# Some capital letters have overhangs that the 'lower case'
# characters can fit under:
r'C[Ja-z\.]': -2,
r'F[Ja-z\.]': -3,
r'T[Ja-z\.]': -5,
r'W[Ja-z\.]': -2,
r'S[Ja-z\.]': -1,
r'V[a-z\.]': -3,
# Left character fits under right character:
r'[alAL][ty479]': -3,
r'a[vwVW]': -2,
r'A[VW]': -3,
r'A[vw]': -2,
r'r[ty479]': -2,
r'[vwVW][Aa]': -2,
r'[Yypv][jJ]': -2,
# Extra space needed:
r'[OUu][Pp]': +1,
}
white_graphics = {
'wibp1': 'P1',
'wibp2': 'P2',

View file

@ -58,7 +58,7 @@ BACKGROUND_COLOR = '#00ffff'
FONT_HEIGHT = 16
# Width of a space character in pixels.
SPACE_WIDTH = 14
SPACE_WIDTH = 10
# Output from 'identify' looks like this:
# fontchars/font033.gif GIF 9x16 9x16+0+0 8-bit sRGB 32c 194B 0.000u 0:00.000
@ -93,10 +93,19 @@ def invoke_command(command):
return subprocess.call(command)
class Font(object):
def __init__(self, fontdir):
def __init__(self, fontdir, kerning_table={}):
self.fontdir = fontdir
self.kerning_table = self.compile_kerning_table(kerning_table)
self.get_font_widths()
def compile_kerning_table(self, kerning_table):
"""Given a dictionary of kerning patterns, compile Regexps."""
result = {}
for pattern, adjust in kerning_table.items():
result[re.compile(pattern)] = adjust
return result
def get_font_widths(self):
charfiles = glob('%s/font*.gif' % self.fontdir)
self.char_widths = {}
@ -116,20 +125,37 @@ class Font(object):
def char_filename(self, c):
return '%s/font%03d.gif' % (self.fontdir, ord(c))
def kerning_adjust(self, char_1, char_2):
"""Get kerning adjustment for pair of characters.
Zero means no adjustment. A negative value adjusts to the
left and a positive value adjusts to the right.
"""
for pattern, adjust in self.kerning_table.items():
if pattern.match(char_1 + char_2):
return adjust
else:
return 0
def iterate_char_positions(self, text):
"""Iterate over characters in string, yielding character with
position it should be placed at in the output file.
"""
x = 0
last_c = ' '
for c in text:
if c == ' ':
x += SPACE_WIDTH
if c not in self:
continue
yield c, x
# Characters overlap by one pixel.
x += self.char_width(c) - 1
if c in self:
x += self.kerning_adjust(last_c, c)
yield c, x
# Characters overlap by one pixel.
x += self.char_width(c) - 1
last_c = c
# We need to add back the missing pixel from the right side
# of the last char.
@ -198,7 +224,7 @@ def generate_graphics(graphics, color=COLOR_WHITE):
print("# %s.gif: '%s'" % (name, text))
font.render_text(text, '%s.gif' % name, color=color)
font = Font('fontchars')
font = Font('fontchars', kerning_table=FONT_KERNING_RULES)
generate_graphics(red_graphics, COLOR_RED)
generate_graphics(blue_graphics, COLOR_BLUE)