from __future__ import division import axi import itertools import string TEXT = ( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ' 'incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis ' 'nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ' 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu ' 'fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in ' 'culpa qui officia deserunt mollit anim id est laborum. ' ) def word_wrap(text, width, measure_func): result = [] for line in text.split('\n'): fields = itertools.groupby(line, lambda x: x.isspace()) fields = [''.join(g) for _, g in fields] if len(fields) % 2 == 1: fields.append('') x = '' for a, b in zip(fields[::2], fields[1::2]): 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 class Font(object): def __init__(self, font, point_size): self.font = font self.max_height = axi.Drawing(axi.text(string.printable, font)).height # self.cap_height = axi.Drawing(axi.text('H', font)).height height = point_size / 72 self.scale = height / self.max_height def text(self, text): d = axi.Drawing(axi.text(text, self.font)) d = d.scale(self.scale) return d def justify_text(self, text, width): d = self.text(text) w = d.width spaces = text.count(' ') if spaces == 0 or w >= width: 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 def main(): font = Font(axi.FUTURAL, 14) d = font.wrap(TEXT, 11.5, 1.5, justify=True) d = d.center(12, 8.5) d.render(bounds=axi.V3_BOUNDS).write_to_png('out.png') if __name__ == '__main__': main()