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