1 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
 
   2 # Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
 
  12     for word in text.split():
 
  14             words[-1] += ' ' + word
 
  17         conj = len(word.lstrip('(').lstrip('[')) == 1
 
  21 class DoesNotFit(Exception):
 
  26     def __init__(self, width, height, texts,
 
  27                  font, lines, leading, tracking,
 
  34         self.font_fallbacks = font_fallbacks
 
  36         self.leading = leading
 
  37         self.tracking = tracking
 
  38         self.align_h = align_h
 
  39         self.align_v = align_v
 
  41         self.margin_top = self.font.getbbox('l')[1]
 
  43         self.glue = self.get_length(' ')
 
  46             (self.get_length(word), word)
 
  47             for word in self.texts
 
  50         self.grouping = self.find_grouping(groups, self.lines, self.glue)
 
  51         if self.grouping is None:
 
  54     def get_font_for_char(self, c):
 
  55         if self.font_fallbacks:
 
  56             for char_range, font in self.font_fallbacks.items():
 
  57                 if char_range[0] <= c <= char_range[1]:
 
  61     def get_length(self, text):
 
  62         text = bidi.get_display(text, base_dir='L')
 
  65             font = self.get_font_for_char(c)
 
  66             if groups and font is groups[-1][0]:
 
  69                 groups.append([font, c])
 
  73             for (font, t) in groups
 
  74         ) + self.tracking * len(text)
 
  76     def text_with_tracking(self, draw, pos, text, fill=None):
 
  78         for c in bidi.get_display(text, base_dir='L'):
 
  79             cfont = self.get_font_for_char(c)
 
  80             width = cfont.getlength(c)
 
  81             draw.text((x, y), c, fill=fill, font=cfont)
 
  82             x += width + self.tracking
 
  84     def as_pil_image(self, color):
 
  85         img = PIL.Image.new('RGBA', (self.width, self.height + 2 * self.margin_top))
 
  86         draw = PIL.ImageDraw.ImageDraw(img)
 
  88         font_letter_height = self.font.getmetrics()[0] - self.margin_top
 
  90         y = self.align_v * (self.height - ((self.lines - 1) * self.leading + font_letter_height))
 
  91         for group in self.grouping:
 
  92             x = (self.width - group[0] + self.tracking) * self.align_h
 
  93             self.align_h *  - group[0] / 2
 
  95                 self.text_with_tracking(
 
 104     def find_grouping(self, groups, ngroups, glue):
 
 110         mean = sum(g[0] for g in groups) + (len(groups) - ngroups) * glue
 
 111         if mean > self.width * ngroups:
 
 114         for grouping in self.all_groupings(groups, ngroups, glue):
 
 115             if max(g[0] for g in grouping) > self.width:
 
 117             var = sum((g[0] - mean) ** 2 for g in grouping)
 
 118             if best is None or best_var > var:
 
 119                 best, best_var = grouping, var
 
 123     def all_groupings(self, groups, ngroups, glue):
 
 126                 yield [(groups[0][0], groups)]
 
 128         next_groups = groups[1:]
 
 129         for grouping in self.all_groupings(next_groups, ngroups, glue):
 
 132                     groups[0][0] + glue + grouping[0][0],
 
 133                     [groups[0]] + grouping[0][1]
 
 137             for grouping in self.all_groupings(next_groups, ngroups - 1, glue):
 
 139                     (groups[0][0], [groups[0]])