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