Drop lots of legacy code. Support Python 3.7-3.11.
[librarian.git] / src / librarian / covers / widgets / author.py
1 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
3 #
4 import PIL.ImageFont
5 from librarian import get_resource
6 from librarian.cover import Metric
7 from ..utils.textbox import TextBox, DoesNotFit, split_words
8 from .base import Widget
9
10
11 class AuthorBox(Widget):
12     font_size = 75
13     leading = 92
14
15     def __init__(self, cover, width):
16         self.width = width
17         self.m = Metric(self, cover.m._scale)
18         super().__init__(cover)
19
20     def setup(self):
21         author_font = PIL.ImageFont.truetype(
22             get_resource('fonts/SourceSans3VF-Roman.ttf'),
23             self.m.font_size,
24             layout_engine=PIL.ImageFont.Layout.BASIC
25         )
26         author_font.set_variation_by_axes([600])
27
28         translator_font = PIL.ImageFont.truetype(
29             get_resource('fonts/SourceSans3VF-Roman.ttf'),
30             self.m.font_size,
31             layout_engine=PIL.ImageFont.Layout.BASIC
32         )
33         translator_font.set_variation_by_axes([400])
34
35         authors = [a.readable() for a in self.cover.book_info.authors]
36         translators = [a.readable() for a in self.cover.book_info.translators]
37         self.textboxes = []
38
39         if authors and translators:
40             # Try with two boxes.
41
42             authors_shortened = False
43             author_box = None
44             while author_box is None:
45                 author_str = ', '.join(authors)
46                 if authors_shortened:
47                     # translate!
48                     author_str += ' i in.'
49                 try:
50                     author_box = TextBox(
51                         self.width,
52                         self.m.leading * 2,
53                         [author_str],
54                         author_font,
55                         1,
56                         self.m.leading,
57                         0,
58                         1, 0
59                     )
60                 except DoesNotFit:
61                     authors.pop()
62                     authors_shortened = True
63
64             translators_shortened = False
65             translator_box = None
66             while translator_box is None:
67                 translator_str = '(tłum. ' + ', '.join(translators)
68                 if translators_shortened:
69                     translator_str += ' i in.'
70                 translator_str += ')'
71                 try:
72                     translator_box = TextBox(
73                         self.width,
74                         self.m.leading * 2,
75                         [translator_str],
76                         translator_font,
77                         1,
78                         self.m.leading,
79                         0,
80                         1, 0
81                     )
82                 except DoesNotFit:
83                     translators.pop()
84                     translators_shortened = True
85
86             self.textboxes = [
87                 author_box,
88                 translator_box
89             ]
90
91         elif authors:
92             author_box = None
93             shortened = False
94             while author_box is None:
95                 if not shortened and len(authors) == 2:
96                     parts = authors
97                 elif len(authors) > 2:
98                     parts = [author + ',' for author in authors[:-1]] + [authors[-1]]
99                     if shortened:
100                         parts.append('i in.')
101                 else:
102                     parts = split_words(authors[0])
103                     if shortened:
104                         parts.append('i in.')
105
106                 try:
107                     if len(parts) > 1:
108                         # Author in two lines.
109                         author_box = TextBox(
110                             self.width,
111                             self.m.leading * 2,
112                             parts,
113                             author_font,
114                             2,
115                             self.m.leading,
116                             0,
117                             1, 0
118                         )
119                     else:
120                         # author in one line.
121                         author_box = TextBox(
122                             self.width,
123                             self.m.leading * 2,
124                             parts,
125                             author_font,
126                             1,
127                             self.m.leading,
128                             0,
129                             1, 0
130                         )
131                 except DoesNotFit:
132                     authors.pop()
133                     shortened = True
134
135             self.textboxes = [author_box]
136
137         if self.textboxes:
138             self.margin_top = self.textboxes[0].margin_top
139
140     def build(self, w, h):
141         img = PIL.Image.new('RGBA', (self.width, self.m.leading * 2))
142         offset = 0
143         for i, tb in enumerate(self.textboxes):
144             sub_img = tb.as_pil_image(self.cover.color_scheme['text'])
145             img.paste(sub_img, (0, self.m.leading * i), sub_img)
146         
147         return img