fb84a790650768ece9e8adecb8447996f76c3b09
[librarian.git] / src / librarian / covers / marquise.py
1 import PIL.Image
2 from librarian.cover import Cover, Metric
3 from .utils.color import algo_contrast_or_hue, luminance, is_very_bright
4 from .utils.textbox import DoesNotFit
5 from .widgets.author import AuthorBox
6 from .widgets.background import Background
7 from .widgets.image import WLLogo, Label
8 from .widgets.marquise import Marquise
9 from .widgets.title import TitleBox
10
11
12 class MarquiseCover(Cover):
13     additional_logos = []
14     square_variant = False
15
16     width = 2100
17     height = 2970
18     margin = 100
19     logo_h = 177
20     author_width = 1300
21
22     title_box_top = 262
23
24     color_schemes = [
25         {
26             'rgb': (0xc3, 0x27, 0x21),
27             'text': '#000',
28         },
29         {
30             'rgb': (0xa0, 0xbf, 0x38),
31             'text': '#000',
32         },
33         {
34             'rgb': (0xed, 0xc0, 0x16),
35             'text': '#000',
36         },
37         {
38             'rgb': (0x47, 0x66, 0x75),
39             'text': '#fff',
40         }
41     ]
42     for c in color_schemes:
43         c['luminance'] = luminance(c['rgb'])
44         cim = PIL.Image.new('RGB', (1, 1))
45         cim.putpixel((0, 0), c['rgb'])
46         cim.convert('HSV')
47         c['hsv'] = cim.getpixel((0, 0))
48
49     
50     def set_size(self, final_width, final_height):
51         if final_width is None:
52             self.m = Metric(self, 1)
53         else:
54             if final_width > self.width:
55                 self.m = Metric(self, final_width / self.width)
56             else:
57                 self.m = Metric(self, 1)
58                 self.scale_after = final_width / self.width
59             
60         if final_height is not None:
61             self.height = round(final_height / self.scale_after / self.m._scale)
62
63         self.square_variant = self.height / self.width < 250 / 210
64
65         marquise_square_small = int(self.width / 2) - 300
66         marquise_square_big = int(self.width / 2) - 100
67         marquise_a4_small = 2970 - self.width
68         marquise_a4_big = marquise_a4_small + 100
69         
70         self.marquise_small = int(round(marquise_square_small + (marquise_a4_small - marquise_square_small) * (self.height - self.width) / (2970 - 2100)))
71         self.marquise_big = int(round(marquise_square_big + (marquise_a4_big - marquise_square_big) * (self.height - self.width) / (2970 - 2100)))
72         self.marquise_xl = self.marquise_big + 200
73
74         if self.marquise_small > self.marquise_big:
75             self.marquise_small = self.marquise_big
76
77     def set_color_scheme_from(self, img):
78         self.color_scheme = algo_contrast_or_hue(img, self.color_schemes)
79         self.is_very_bright = is_very_bright(img)
80
81     def image(self):
82         img = PIL.Image.new('RGB', (self.m.width, self.m.height), self.background_color)
83         
84         bg = Background(self)
85
86         if self.square_variant:
87             layout_options = [
88                 (self.m.marquise_small, 1),
89                 (self.m.marquise_big, 2),
90                 (self.m.marquise_big, 3),
91                 (self.m.marquise_big, None),
92             ]
93         else:
94             layout_options = [
95                 (self.m.marquise_small, 2),
96                 (self.m.marquise_small, 1),
97                 (self.m.marquise_big, 3),
98                 (self.m.marquise_xl, 4),
99                 (self.m.marquise_xl, None),
100             ]
101
102         for marquise_h, lines in layout_options:
103             title_box_height = marquise_h - self.m.title_box_top - self.m.margin
104             try:
105                 title_box = TitleBox(
106                     self,
107                     self.m.width - 2 * self.m.margin,
108                     title_box_height,
109                     lines,
110                     force=lines is None
111                 )
112             except DoesNotFit:
113                 continue
114             else:
115                 break
116
117         self.marquise_height = marquise_h
118         marquise = Marquise(self, marquise_h)
119
120         bg.apply(
121             img,
122             0, marquise.edge_top,
123             self.m.width, self.m.height - marquise.edge_top
124         )
125         self.set_color_scheme_from(
126             img.crop((
127                 0, marquise.edge_top,
128                 self.m.width, marquise.edge_top + (
129                     self.m.height - marquise.edge_top
130                 ) / 4
131             ))
132         )
133
134         marquise.apply(
135             img, 0, 0, self.m.width
136         )
137         title_box.apply(
138             img,
139             marquise.title_box_position[0],
140             marquise.title_box_position[1],
141         )
142
143         AuthorBox(self, self.m.author_width).apply(
144             img, self.m.width - self.m.margin - self.m.author_width, self.m.margin
145         )
146         WLLogo(self).apply(img, self.m.margin, self.m.margin, None, self.m.logo_h)
147
148                               
149         for logo in self.additional_logos:
150             LogoSticker(self, logo).apply(img, 0, 0)
151
152
153         return img
154
155
156     
157 class LabelMarquiseCover(MarquiseCover):
158     label_left = 95
159     label_top = 105
160     label_w = 710
161     label_h = 710
162     
163     def image(self):
164         img = super().image()
165
166         Label(self).apply(
167             img,
168             self.m.label_left,
169             self.marquise_height - self.m.label_top,
170             self.m.label_w,
171             self.m.label_h
172         )
173
174         return img