Limit image size, fixes #4464.
[librarian.git] / src / librarian / cover.py
index b60ec34..3581f59 100644 (file)
@@ -1,17 +1,13 @@
-# -*- coding: utf-8 -*-
-#
 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
 #
 #
-from __future__ import unicode_literals
-
 import re
 from PIL import Image, ImageFont, ImageDraw, ImageFilter
 import re
 from PIL import Image, ImageFont, ImageDraw, ImageFilter
-from six import BytesIO
+from io import BytesIO
 from librarian import get_resource, OutputFile, URLOpener
 
 
 from librarian import get_resource, OutputFile, URLOpener
 
 
-class Metric(object):
+class Metric:
     """Gets metrics from an object, scaling it by a factor."""
     def __init__(self, obj, scale):
         self._obj = obj
     """Gets metrics from an object, scaling it by a factor."""
     def __init__(self, obj, scale):
         self._obj = obj
@@ -25,7 +21,7 @@ class Metric(object):
             return src
 
 
             return src
 
 
-class TextBox(object):
+class TextBox:
     """Creates an Image with a series of centered strings."""
 
     SHADOW_X = 3
     """Creates an Image with a series of centered strings."""
 
     SHADOW_X = 3
@@ -72,7 +68,7 @@ class TextBox(object):
                     break
                 line = parts[0]
 
                     break
                 line = parts[0]
 
-                if line[-2] == ' ':
+                if len(line) > 2 and line[-2] == ' ':
                     line = line[:-2]
 
                 line_width = self.draw.textsize(line, font=font)[0]
                     line = line[:-2]
 
                 line_width = self.draw.textsize(line, font=font)[0]
@@ -108,7 +104,7 @@ class TextBox(object):
         return image
 
 
         return image
 
 
-class Cover(object):
+class Cover:
     """Abstract base class for cover images generator."""
     width = 600
     height = 800
     """Abstract base class for cover images generator."""
     width = 600
     height = 800
@@ -153,11 +149,21 @@ class Cover(object):
 
     def __init__(self, book_info, format=None, width=None, height=None, cover_logo=None):
         self.book_info = book_info
 
     def __init__(self, book_info, format=None, width=None, height=None, cover_logo=None):
         self.book_info = book_info
+
+        self.predesigned = False
+        if book_info.cover_class == 'image':
+            self.predesigned = True
+
+        # TODO: deprecated
+        if book_info.cover_box_position == 'none':
+            self.predesigned = True
+
         self.authors = [auth.readable() for auth in book_info.authors]
         self.title = book_info.title
         if format is not None:
             self.format = format
         self.set_size(width, height)
         self.authors = [auth.readable() for auth in book_info.authors]
         self.title = book_info.title
         if format is not None:
             self.format = format
         self.set_size(width, height)
+        self.cover_logo = cover_logo
 
     def set_size(self, width, height):
         if width and height:
 
     def set_size(self, width, height):
         if width and height:
@@ -207,7 +213,7 @@ class Cover(object):
 
         author_font = ImageFont.truetype(
             self.author_font_ttf, metr.author_font_size,
 
         author_font = ImageFont.truetype(
             self.author_font_ttf, metr.author_font_size,
-            layout_engine=ImageFont.LAYOUT_BASIC)
+            layout_engine=ImageFont.Layout.BASIC)
         for pa in self.pretty_authors():
             tbox.text(pa, self.author_color, author_font, metr.author_lineskip,
                       self.author_shadow)
         for pa in self.pretty_authors():
             tbox.text(pa, self.author_color, author_font, metr.author_lineskip,
                       self.author_shadow)
@@ -221,7 +227,7 @@ class Cover(object):
             )
         title_font = ImageFont.truetype(
             self.title_font_ttf, metr.title_font_size,
             )
         title_font = ImageFont.truetype(
             self.title_font_ttf, metr.title_font_size,
-            layout_engine=ImageFont.LAYOUT_BASIC)
+            layout_engine=ImageFont.Layout.BASIC)
         tbox.text(self.pretty_title(), self.title_color, title_font,
                   metr.title_lineskip, self.title_shadow)
         text_img = tbox.image()
         tbox.text(self.pretty_title(), self.title_color, title_font,
                   metr.title_lineskip, self.title_shadow)
         text_img = tbox.image()
@@ -235,7 +241,7 @@ class Cover(object):
             img = img.resize((
                     int(round(img.size[0] * self.scale_after)),
                     int(round(img.size[1] * self.scale_after))),
             img = img.resize((
                     int(round(img.size[0] * self.scale_after)),
                     int(round(img.size[1] * self.scale_after))),
-                Image.ANTIALIAS)
+                Image.Resampling.LANCZOS)
         return img
 
     def mime_type(self):
         return img
 
     def mime_type(self):
@@ -297,22 +303,22 @@ class WLCover(Cover):
     format = 'JPEG'
 
     epoch_colors = {
     format = 'JPEG'
 
     epoch_colors = {
-        u'Starożytność': '#9e3610',
-        u'Średniowiecze': '#564c09',
-        u'Renesans': '#8ca629',
-        u'Barok': '#a6820a',
-        u'Oświecenie': '#f2802e',
-        u'Romantyzm': '#db4b16',
-        u'Pozytywizm': '#961060',
-        u'Modernizm': '#7784e0',
-        u'Dwudziestolecie międzywojenne': '#3044cf',
-        u'Współczesność': '#06393d',
+        'Starożytność': '#9e3610',
+        'Średniowiecze': '#564c09',
+        'Renesans': '#8ca629',
+        'Barok': '#a6820a',
+        'Oświecenie': '#f2802e',
+        'Romantyzm': '#db4b16',
+        'Pozytywizm': '#961060',
+        'Modernizm': '#7784e0',
+        'Dwudziestolecie międzywojenne': '#3044cf',
+        'Współczesność': '#06393d',
     }
     set_title_color = True
 
     kind_box_position = {
     }
     set_title_color = True
 
     kind_box_position = {
-        u'Liryka': 'top',
-        u'Epika': 'bottom',
+        'Liryka': 'top',
+        'Epika': 'bottom',
     }
 
     def __init__(self, book_info, format=None, width=None, height=None,
     }
 
     def __init__(self, book_info, format=None, width=None, height=None,
@@ -378,7 +384,7 @@ class WLCover(Cover):
                       )
         author_font = ImageFont.truetype(
             self.author_font_ttf, metr.author_font_size,
                       )
         author_font = ImageFont.truetype(
             self.author_font_ttf, metr.author_font_size,
-            layout_engine=ImageFont.LAYOUT_BASIC)
+            layout_engine=ImageFont.Layout.BASIC)
         for pa in self.pretty_authors():
             box.text(pa, font=author_font, line_height=metr.author_lineskip,
                      color=self.author_color, shadow_color=self.author_shadow,
         for pa in self.pretty_authors():
             box.text(pa, font=author_font, line_height=metr.author_lineskip,
                      color=self.author_color, shadow_color=self.author_shadow,
@@ -395,7 +401,7 @@ class WLCover(Cover):
         # Write title.
         title_font = ImageFont.truetype(
             self.title_font_ttf, metr.title_font_size,
         # Write title.
         title_font = ImageFont.truetype(
             self.title_font_ttf, metr.title_font_size,
-            layout_engine=ImageFont.LAYOUT_BASIC)
+            layout_engine=ImageFont.Layout.BASIC)
         box.text(self.pretty_title(),
                  line_height=metr.title_lineskip,
                  font=title_font,
         box.text(self.pretty_title(),
                  line_height=metr.title_lineskip,
                  font=title_font,
@@ -499,7 +505,7 @@ class WLCover(Cover):
                     cut = 0
                 else:
                     cut = (resized[1] - trg_size[1]) // 2
                     cut = 0
                 else:
                     cut = (resized[1] - trg_size[1]) // 2
-                src = src.resize(resized, Image.ANTIALIAS)
+                src = src.resize(resized, Image.Resampling.LANCZOS)
                 src = src.crop((0, cut, src.size[0], src.size[1] - cut))
             else:
                 resized = (
                 src = src.crop((0, cut, src.size[0], src.size[1] - cut))
             else:
                 resized = (
@@ -507,7 +513,7 @@ class WLCover(Cover):
                     trg_size[1],
                 )
                 cut = (resized[0] - trg_size[0]) // 2
                     trg_size[1],
                 )
                 cut = (resized[0] - trg_size[0]) // 2
-                src = src.resize(resized, Image.ANTIALIAS)
+                src = src.resize(resized, Image.Resampling.LANCZOS)
                 src = src.crop((cut, 0, src.size[0] - cut, src.size[1]))
 
             img.paste(src, (metr.bar_width, 0))
                 src = src.crop((cut, 0, src.size[0] - cut, src.size[1]))
 
             img.paste(src, (metr.bar_width, 0))
@@ -662,7 +668,7 @@ class LogoWLCover(WLCover):
                         logo.size[1] * widths[i] / logo.size[0] * L_scale
                     ))
                 ),
                         logo.size[1] * widths[i] / logo.size[0] * L_scale
                     ))
                 ),
-                Image.ANTIALIAS)
+                Image.Resampling.LANCZOS)
             if self.logos_right:
                 cursor -= logo.size[0]
 
             if self.logos_right:
                 cursor -= logo.size[0]
 
@@ -685,7 +691,7 @@ class LogoWLCover(WLCover):
             draw = ImageDraw.Draw(img2)
             author_font = ImageFont.truetype(
                 self.author_font_ttf, metr.annotation_height,
             draw = ImageDraw.Draw(img2)
             author_font = ImageFont.truetype(
                 self.author_font_ttf, metr.annotation_height,
-                layout_engine=ImageFont.LAYOUT_BASIC)
+                layout_engine=ImageFont.Layout.BASIC)
             draw.text((self.annotation_height, self.annotation_height), self.annotation, font=author_font, fill='#FFFFFF')
             img2.show()
             img2 = img2.rotate(90)
             draw.text((self.annotation_height, self.annotation_height), self.annotation, font=author_font, fill='#FFFFFF')
             img2.show()
             img2 = img2.rotate(90)
@@ -875,7 +881,7 @@ class PrestigioCover(Cover):
     title_font_size = 50
 
     def pretty_title(self):
     title_font_size = 50
 
     def pretty_title(self):
-        return u"„%s”" % self.title
+        return "„%s”" % self.title
 
 
 class BookotekaCover(Cover):
 
 
 class BookotekaCover(Cover):
@@ -989,7 +995,7 @@ class FactoryCover(LogoWLCover):
 from librarian.covers.marquise import MarquiseCover, LabelMarquiseCover
 
 COVER_CLASSES = {
 from librarian.covers.marquise import MarquiseCover, LabelMarquiseCover
 
 COVER_CLASSES = {
-    'default': LogoWLCover,
+    'legacy': LogoWLCover,
     'kmlu': KMLUCover,
     'mpw': MPWCover,
     'atrium': AtriumCover,
     'kmlu': KMLUCover,
     'mpw': MPWCover,
     'atrium': AtriumCover,
@@ -1000,13 +1006,15 @@ COVER_CLASSES = {
     'factory': FactoryCover,
     'm': MarquiseCover,
     'm-label': LabelMarquiseCover,
     'factory': FactoryCover,
     'm': MarquiseCover,
     'm-label': LabelMarquiseCover,
+    'default': MarquiseCover,
 }
 
 
 def make_cover(book_info, *args, **kwargs):
 }
 
 
 def make_cover(book_info, *args, **kwargs):
+    cover_class_name = None
     if 'cover_class' in kwargs:
         cover_class_name = kwargs.pop('cover_class')
     if 'cover_class' in kwargs:
         cover_class_name = kwargs.pop('cover_class')
-    else:
-        cover_class_name = book_info.cover_class
+    if not cover_class_name:
+        cover_class_name = 'default'
     cover_class = COVER_CLASSES[cover_class_name]
     return cover_class(book_info, *args, **kwargs)
     cover_class = COVER_CLASSES[cover_class_name]
     return cover_class(book_info, *args, **kwargs)