better text handling

This commit is contained in:
Michael Fogleman 2018-03-04 19:36:22 -05:00
parent 76d5ca1cd1
commit e1c2eacd8a
3 changed files with 68 additions and 28 deletions

View File

@ -243,7 +243,7 @@ class Drawing(object):
paths.append(path) paths.append(path)
return Drawing(paths) return Drawing(paths)
def render(self, scale=109, margin=1, line_width=0.5/25.4, def render(self, scale=109, margin=1, line_width=0.35/25.4,
bounds=None, show_bounds=True, bounds=None, show_bounds=True,
use_axi_bounds=False, show_axi_bounds=False): use_axi_bounds=False, show_axi_bounds=False):
if cairo is None: if cairo is None:

View File

@ -1,3 +1,5 @@
from __future__ import division
from .hershey_fonts import * from .hershey_fonts import *
def text(string, font=FUTURAL, spacing=0, extra=0): def text(string, font=FUTURAL, spacing=0, extra=0):
@ -18,29 +20,67 @@ def text(string, font=FUTURAL, spacing=0, extra=0):
x += extra x += extra
return result return result
def text_width(string, font=FUTURAL, spacing=0): def _word_wrap(text, width, measure_func):
x = 0 result = []
for ch in string: for line in text.split('\n'):
index = ord(ch) - 32 fields = itertools.groupby(line, lambda x: x.isspace())
if index < 0 or index >= 96: fields = [''.join(g) for _, g in fields]
x += spacing if len(fields) % 2 == 1:
continue fields.append('')
lt, rt, coords = font[index] x = ''
x += rt - lt + spacing for a, b in zip(fields[::2], fields[1::2]):
return x w, _ = measure_func(x + a)
if w > width:
if x == '':
result.append(a)
continue
else:
result.append(x)
x = ''
x += a + b
if x != '':
result.append(x)
result = [x.strip() for x in result]
return result
def justify_text(lines, font=FUTURAL, spacing=0): class Font(object):
widths = [text_width(x, font, spacing) for x in lines] def __init__(self, font, point_size):
max_width = max(widths) self.font = font
extras = [] self.max_height = axi.Drawing(axi.text(string.printable, font)).height
for i, (line, width) in enumerate(zip(lines, widths)): self.scale = (point_size / 72) / self.max_height
spaces = line.count(' ') def text(self, text):
if spaces == 0: d = axi.Drawing(axi.text(text, self.font))
e = 0 d = d.scale(self.scale)
else: return d
e = float(max_width - width) / spaces def justify_text(self, text, width):
if i == len(lines) - 1: d = self.text(text)
e = 0 w = d.width
extras.append(e) spaces = text.count(' ')
print width, max_width, spaces, e if spaces == 0 or w >= width:
return [text(line, font, spacing, extra) for line, extra in zip(lines, extras)] return d
e = ((width - w) / spaces) / self.scale
d = axi.Drawing(axi.text(text, self.font, extra=e))
d = d.scale(self.scale)
return d
def measure(self, text):
return self.text(text).size
def wrap(self, text, width, line_spacing=1, align=0, justify=False):
lines = _word_wrap(text, width, self.measure)
ds = [self.text(line) for line in lines]
max_width = max(d.width for d in ds)
if justify:
jds = [self.justify_text(line, max_width) for line in lines]
ds = jds[:-1] + [ds[-1]]
spacing = line_spacing * self.max_height * self.scale
result = axi.Drawing()
y = 0
for d in ds:
if align == 0:
x = 0
elif align == 1:
x = max_width - d.width
else:
x = max_width / 2 - d.width / 2
result.add(d.translate(x, y))
y += spacing
return result

View File

@ -81,8 +81,8 @@ class Font(object):
return result return result
def main(): def main():
font = Font(axi.FUTURAL, 18) font = Font(axi.FUTURAL, 14)
d = font.wrap(TEXT * 2, 12, 1.5, justify=True) d = font.wrap(TEXT, 11.5, 1.5, justify=True)
d = d.center(12, 8.5) d = d.center(12, 8.5)
d.render(bounds=axi.V3_BOUNDS).write_to_png('out.png') d.render(bounds=axi.V3_BOUNDS).write_to_png('out.png')