play-daemon/daemon/thumbnailer.py
2022-03-31 17:10:34 +02:00

117 lines
4.5 KiB
Python

import logging
import os
import re
import textwrap
from PIL import Image, ImageDraw, ImageFont
def scale_box(inbox, imgsize):
(i1x, i1y, i2x, i2y) = inbox
(w, h) = imgsize
return (i1x*w, i1y*h,
i2x*w, i2y*h)
def max_size(draw, inbox, text, font, size):
anchor='lt'
if '\n' in text:
anchor=None
f = ImageFont.truetype(font, size)
(i1x, i1y, i2x, i2y) = inbox
(b1x, b1y, b2x, b2y) = draw.textbbox((i1x, i1y), text,
font=f, anchor=anchor)
if (b1x < i1x or b1y < i1y or
b2x > i2x or b2y > i2y):
return max_size(draw, inbox, text, font, size-5)
return size
def fix_outliers(text):
modifiers = [('[ÖQ]', 'O'),
('[ÅÄ]', 'A'),
('[yqpg]', 'u'),
('j', 'i')]
for (pat, rep) in modifiers:
text = re.sub(pat, rep, text)
return text
class Thumbnailer:
def __init__(self, config, ldap):
self.base = config['base']
self.fill = config['textcolor']
self.ldap = ldap
self.logger = logging.getLogger('play-daemon')
self.thumbname = 'thumb.png'
self.font = 'verdana.ttf'
self.titlebox = (1/8, 0.4,
7/8, 0.5)
self.descrbox = (1/8, 0.55,
7/8, 0.8)
def create_if_missing(self, package):
if not package['thumb']:
title = package['title']['sv']
description = package['description']
courses = ', '.join(package['courses'])
presenters = ', '.join([self.ldap.get_name(uid)
for uid in package['presenters']])
extras = []
if courses:
extras.append(courses)
if presenters:
extras.append(presenters)
extra = ': '.join(extras)
workbase = package['workbase']
pres_id = package['id']
self.logger.debug('%s - Creating thumbnail', pres_id)
self.logger.debug('%s - Title: %s', pres_id, title)
self.logger.debug('%s - Description: %s', pres_id, description)
self.logger.debug('%s - Extra: %s', pres_id, extra)
package['thumb'] = self.make_thumb(workbase,
title, description, extra)
self.logger.info('%s - Thumbnail created', pres_id)
return package
def make_thumb(self, workbase, title, description, extra):
with Image.open(self.base) as im:
draw = ImageDraw.Draw(im)
# Size and draw title
s_titlebox = scale_box(self.titlebox, im.size)
(t1x, t1y, t2x, t2y) = s_titlebox
title_size = max_size(draw, s_titlebox, fix_outliers(title),
self.font, 140)
draw.text((t1x, t2y), title, fill=self.fill, anchor='ls',
font=ImageFont.truetype(self.font, title_size))
# Size and draw description
s_descrbox = scale_box(self.descrbox, im.size)
(d1x, d1y, d2x, d2y) = s_descrbox
descr = textwrap.fill(description)
descr_size = max_size(draw, s_descrbox, descr, self.font, 75)
f = ImageFont.truetype(self.font, descr_size)
draw.multiline_text((d1x, d1y), descr, fill=self.fill, font=f)
# Size and draw extra
if extra:
# Get effective size of the description text
(b1x, b1y, b2x, b2y) = draw.textbbox((d1x, d1y),
descr,
font=f)
# Create a preliminary bounding box for extra
extrabox = (d1x, b2y,
d2x, im.height)
# Make sure the text fits in the box
extra_size = max_size(draw, extrabox, extra,
self.font, 50)
# Offset the extra box by one line height
extrabox = (extrabox[0], extrabox[1] + extra_size,
extrabox[2], extrabox[3])
(p1x, p1y, p2x, p2y) = extrabox
f = ImageFont.truetype(self.font, extra_size)
# Draw it
draw.text((p1x, p1y), extra, fill=self.fill,
font=f, anchor='lt')
im.save(os.path.join(workbase, self.thumbname))
return self.thumbname