+# This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
+#
import PIL.Image
import PIL.ImageDraw
+import bidi
def split_words(text):
return words
-
-def text_with_tracking(draw, tracking, pos, text, fill=None, font=None):
- x, y = pos
- for c in text:
- width = font.getsize(c)[0]
- draw.text((x, y), c, fill=fill, font=font)
- x += width + tracking
-
-
class DoesNotFit(Exception):
pass
class TextBox:
def __init__(self, width, height, texts,
font, lines, leading, tracking,
- align_h, align_v):
+ align_h, align_v,
+ font_fallbacks=None):
self.width = width
self.height = height
self.texts = texts
self.font = font
+ self.font_fallbacks = font_fallbacks
self.lines = lines
self.leading = leading
self.tracking = tracking
if self.grouping is None:
raise DoesNotFit()
+ def get_font_for_char(self, c):
+ if self.font_fallbacks:
+ for char_range, font in self.font_fallbacks.items():
+ if char_range[0] <= c <= char_range[1]:
+ return font
+ return self.font
+
def get_length(self, text):
- return self.font.getlength(text) + self.tracking * len(text)
-
+ text = bidi.get_display(text, base_dir='L')
+ groups = []
+ for c in text:
+ font = self.get_font_for_char(c)
+ if groups and font is groups[-1][0]:
+ groups[-1][1] += c
+ else:
+ groups.append([font, c])
+
+ return sum(
+ font.getlength(t)
+ for (font, t) in groups
+ ) + self.tracking * len(text)
+
+ def text_with_tracking(self, draw, pos, text, fill=None):
+ x, y = pos
+ for c in bidi.get_display(text, base_dir='L'):
+ cfont = self.get_font_for_char(c)
+ width = cfont.getlength(c)
+ draw.text((x, y), c, fill=fill, font=cfont)
+ x += width + self.tracking
+
def as_pil_image(self, color):
img = PIL.Image.new('RGBA', (self.width, self.height + 2 * self.margin_top))
draw = PIL.ImageDraw.ImageDraw(img)
x = (self.width - group[0] + self.tracking) * self.align_h
self.align_h * - group[0] / 2
for s, w in group[1]:
- text_with_tracking(
- draw, self.tracking, (x, y),
- w, fill=color, font=self.font
+ self.text_with_tracking(
+ draw, (x, y),
+ w, fill=color
)
x += s + self.glue
y += self.leading
def find_grouping(self, groups, ngroups, glue):
best = None
best_var = None
+ if not groups:
+ return []
mean = sum(g[0] for g in groups) + (len(groups) - ngroups) * glue
if mean > self.width * ngroups: