Add custom thumbnailer

This commit is contained in:
Raphael Michel
2018-03-20 09:33:15 +01:00
parent 840cee206a
commit e7458f3032
16 changed files with 158 additions and 25 deletions

View File

@@ -0,0 +1,9 @@
from django.apps import AppConfig
class PretixHelpersConfig(AppConfig):
name = 'pretix.helpers'
label = 'pretixhelpers'
default_app_config = 'pretix.helpers.PretixHelpersConfig'

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2018-03-20 07:36
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Thumbnail',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('source', models.CharField(max_length=255)),
('size', models.CharField(max_length=255)),
('thumb', models.FileField(upload_to='')),
],
),
migrations.AlterUniqueTogether(
name='thumbnail',
unique_together=set([('source', 'size')]),
),
]

View File

@@ -0,0 +1,10 @@
from django.db import models
class Thumbnail(models.Model):
source = models.CharField(max_length=255)
size = models.CharField(max_length=255)
thumb = models.FileField(upload_to='pub/thumbs/')
class Meta:
unique_together = (('source', 'size'),)

View File

@@ -0,0 +1,18 @@
import logging
from django import template
from django.core.files.storage import default_storage
from pretix.helpers.thumb import get_thumbnail
register = template.Library()
logger = logging.getLogger(__name__)
@register.filter
def thumb(source, arg):
try:
return get_thumbnail(source, arg).thumb.url
except:
logger.exception('Failed to create thumbnail')
return default_storage.url(source)

View File

@@ -0,0 +1,75 @@
import hashlib
from io import BytesIO
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from PIL import Image
from pretix.helpers.models import Thumbnail
class ThumbnailError(Exception):
pass
def get_sizes(size, imgsize):
crop = False
if size.endswith('^'):
crop = True
size = size[:-1]
if 'x' in size:
size = [int(p) for p in size.split('x')]
else:
size = [int(size), int(size)]
if crop:
wfactor = min(1, size[0] / imgsize[0])
hfactor = min(1, size[1] / imgsize[1])
if wfactor > hfactor:
return (int(size[0]), int(imgsize[1] * hfactor)), \
(0, int((imgsize[1] * wfactor - size[1]) / 2), size[0], int((imgsize[1] * wfactor + size[1]) / 2))
else:
return (int(imgsize[0] * hfactor), int(size[1])), \
(int((imgsize[0] * hfactor - size[0]) / 2), 0, int((imgsize[0] * hfactor + size[0]) / 2), size[1])
else:
wfactor = min(1, size[0] / imgsize[0])
hfactor = min(1, size[1] / imgsize[1])
if wfactor < hfactor:
return (size[0], int(imgsize[1] * wfactor)), None
else:
return (int(imgsize[0] * hfactor), size[1]), None
def create_thumbnail(source, size):
if isinstance(source, str):
source = default_storage.open(source)
image = Image.open(BytesIO(source.read()))
try:
image.load()
except:
raise ThumbnailError('Could not load image')
scale, crop = get_sizes(size, image.size)
image = image.resize(scale)
print(scale, crop)
if crop:
image = image.crop(crop)
checksum = hashlib.md5(image.tobytes()).hexdigest()
name = checksum + '.' + size.replace('^', 'c') + '.png'
buffer = BytesIO()
image.save(fp=buffer, format='PNG')
imgfile = ContentFile(buffer.getvalue())
t = Thumbnail.objects.create(source=source, size=size)
t.thumb.save(name, imgfile)
return t
def get_thumbnail(source, size):
# Assumes files are immutable
try:
return Thumbnail.objects.get(source=source, size=size)
except Thumbnail.DoesNotExist:
return create_thumbnail(source, size)