fix pdf rendering on production
[librarian.git] / librarian / formats / cover / wolnelektury / __init__.py
1 # -*- coding: utf-8 -*-
2 #
3 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
4 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
5 #
6 from PIL import Image, ImageFont, ImageDraw
7 from PIL import ImageEnhance
8
9 from librarian.utils import get_resource
10 from .. import Cover, Metric, TextBox
11
12
13 class WLCover(Cover):
14     """Default Wolne Lektury cover generator."""
15     format_name = u"WL-style cover image"
16
17     width = 600
18     height = 833
19     uses_dc_cover = True
20     author_font_ttf = get_resource('fonts/JunicodeWL-Regular.ttf')
21     author_font_size = 20
22     author_lineskip = 30
23     title_font_ttf = get_resource('fonts/DejaVuSerif-Bold.ttf')
24     title_font_size = 30
25     title_lineskip = 40
26     title_box_width = 350
27     
28     box_top_margin = 100
29     box_bottom_margin = 100
30     box_padding_y = 20
31     box_above_line = 10
32     box_below_line = 15
33     box_line_left = 75
34     box_line_right = 275
35     box_line_width = 2
36
37     logo_top = 15
38     logo_width = 140
39
40     bar_width = 35
41     background_color = '#444'
42     author_color = '#444'
43     default_background = get_resource('res/cover.png')
44     format = 'JPEG'
45
46     epoch_colors = {
47         u'Starożytność': '#9e3610',
48         u'Średniowiecze': '#564c09',
49         u'Renesans': '#8ca629',
50         u'Barok': '#a6820a',
51         u'Oświecenie': '#f2802e',
52         u'Romantyzm': '#db4b16',
53         u'Pozytywizm': '#961060',
54         u'Modernizm': '#7784e0',
55         u'Dwudziestolecie międzywojenne': '#3044cf',
56         u'Współczesność': '#06393d',
57     }
58
59     def __init__(self, doc, format=None, width=None, height=None, with_logo=False):
60         super(WLCover, self).__init__(doc, format=format, width=width, height=height)
61         self.kind = doc.meta.get_one('kind')
62         self.epoch = doc.meta.get_one('epoch')
63         self.with_logo = with_logo
64         # TODO
65         # if doc.meta.get('cover_url'):
66         #     url = doc.meta.get('cover_url')[0]
67         #     bg_src = None
68         #     if bg_src is None:
69         #         bg_src = URLOpener().open(url)
70         #     self.background_img = StringIO(bg_src.read())
71         #     bg_src.close()
72         # else:
73         self.background_img = self.default_background
74
75     def pretty_author(self):
76         return self.author.upper()
77
78     def image(self):
79         metr = Metric(self, self.scale)
80         img = Image.new('RGB', (metr.width, metr.height), self.background_color)
81         draw = ImageDraw.Draw(img)
82
83         if self.epoch in self.epoch_colors:
84             epoch_color = self.epoch_colors[self.epoch]
85         else:
86             epoch_color = '#000'
87         draw.rectangle((0, 0, metr.bar_width, metr.height), fill=epoch_color)
88
89         if self.background_img:
90             src = Image.open(self.background_img)
91             trg_size = (metr.width - metr.bar_width, metr.height)
92             if src.size[0] * trg_size[1] < src.size[1] * trg_size[0]:
93                 resized = (
94                     trg_size[0],
95                     src.size[1] * trg_size[0] / src.size[0]
96                 )
97                 cut = (resized[1] - trg_size[1]) / 2
98                 src = src.resize(resized, Image.ANTIALIAS)
99                 src = src.crop((0, cut, src.size[0], src.size[1] - cut))
100             else:
101                 resized = (
102                     src.size[0] * trg_size[1] / src.size[1],
103                     trg_size[1],
104                 )
105                 cut = (resized[0] - trg_size[0]) / 2
106                 src = src.resize(resized, Image.ANTIALIAS)
107                 src = src.crop((cut, 0, src.size[0] - cut, src.size[1]))
108
109             img.paste(src, (metr.bar_width, 0))
110             del src
111
112         box = TextBox(metr.title_box_width, metr.height, padding_y=metr.box_padding_y)
113         author_font = ImageFont.truetype(
114             self.author_font_ttf, metr.author_font_size)
115         box.text(
116             self.pretty_author(),
117             font=author_font,
118             line_height=metr.author_lineskip,
119             color=self.author_color,
120             shadow_color=self.author_shadow,
121         )
122
123         box.skip(metr.box_above_line)
124         box.draw.line(
125             (metr.box_line_left, box.height, metr.box_line_right, box.height),
126             fill=self.author_color, width=metr.box_line_width)
127         box.skip(metr.box_below_line)
128
129         title_font = ImageFont.truetype(
130             self.title_font_ttf, metr.title_font_size)
131         box.text(
132             self.pretty_title(),
133             line_height=metr.title_lineskip,
134             font=title_font,
135             color=epoch_color,
136             shadow_color=self.title_shadow,
137         )
138
139         if self.with_logo:
140             logo = Image.open(get_resource('res/wl-logo-mono.png'))
141             logo = logo.resize((metr.logo_width, logo.size[1] * metr.logo_width / logo.size[0]), Image.ANTIALIAS)
142             alpha = logo.split()[3]
143             alpha = ImageEnhance.Brightness(alpha).enhance(.75)
144             logo.putalpha(alpha)
145             box.skip(metr.logo_top + logo.size[1])
146
147         box_img = box.image()
148
149         if self.kind == 'Liryka':
150             # top
151             box_top = metr.box_top_margin
152         elif self.kind == 'Epika':
153             # bottom
154             box_top = metr.height - metr.box_bottom_margin - box_img.size[1]
155         else:
156             # center
157             box_top = (metr.height - box_img.size[1]) / 2
158
159         box_left = metr.bar_width + (metr.width - metr.bar_width - box_img.size[0]) / 2
160         draw.rectangle((box_left, box_top, box_left + box_img.size[0], box_top + box_img.size[1]), fill='#fff')
161         img.paste(box_img, (box_left, box_top), box_img)
162
163         if self.with_logo:
164             img.paste(
165                 logo,
166                 (box_left + (box_img.size[0] - logo.size[0]) / 2,
167                     box_top + box_img.size[1] - metr.box_padding_y - logo.size[1]), mask=logo)
168
169         return img