Lightweight Django Thumbnails
Posted by Richard Cooper | Filed under Uncategorized
I needed a good thumbnail solution for a recent Django project but didn’t want the overhead of using sorl – I just needed a simple template tag that would let me generate the correct size of thumbnail from the main picture.
I found a solution on djangosnippets.org but it needed a little tweeking to suit my needs.
The filter is applied directly to an image field using a template tag such as
{{ object.image|make_thumbnail:'100x200' }}and supposing the image filename is “image.jpg”, it checks if there is a file called “image_100x200.jpg”, if the file isn’t there, it resizes and saves the original image, finally it returns the proper url to the resized image.
The updated filter is given below (you will need PIL installed):
import os import Image from django.template import Library, Node from django.template import Variable, resolve_variable from django.core.urlresolvers import reverse from django.contrib.contenttypes.models import ContentType register = Library() def make_thumbnail(file, size='200x200'): """ Example: <img src="object.get_image_url" alt="original image" /> <img src="object.image|make_thumbnail" alt="image resized to default 200x200 format" /> <img src="object.image|make_thumbnail:'200x300'" alt="image resized to 200x300" /> The filter is applied to a image field (not the image url get from get_image_url method of the model), supposing the image filename is "image.jpg", it checks if there is a file called "image_200x200.jpg" or "image_200x300.jpg" on the second case, if the file isn't there, it resizes the original image, finally it returns the proper url to the resized image. """ if file: # defining the size x, y = [int(x) for x in size.split('x')] # defining the filename and the miniature filename basename, format = file.path.rsplit('.', 1) baseurl, _format = file.url.rsplit('.', 1) miniature_filename = basename + '_' + size + '.' + format miniature_url = baseurl + '_' + size + '.' + format # if the image wasn't already resized, resize it if not os.path.exists(miniature_filename): image = Image.open(file.path) pw = image.size[0] ph = image.size[1] nw = x nh = y pr = float(pw) / float(ph) nr = float(nw) / float(nh) if image.mode not in ('L', 'RGB'): image = image.convert('RGB') if pw == nw and ph == nh: pass else: if pr > nr: # image aspect is wider than destination ratio tw = int(round(nh * pr)) image = image.resize((tw, nh), Image.ANTIALIAS) l = int(round(( tw - nw ) / 2.0)) image = image.crop((l, 0, l + nw, nh)) elif pr < nr: # image aspect is taller than destination ratio th = int(round(nw / pr)) image = image.resize((nw, th), Image.ANTIALIAS) t = int(round(( th - nh ) / 2.0)) image = image.crop((0, t, nw, t + nh)) else: # image aspect matches the destination ratio image = image.resize(size, Image.ANTIALIAS) image.save(miniature_filename, image.format) return miniature_url return '' register.filter(make_thumbnail)
Save it as something like thumbs_filter.py in a templatetag folder in one of your django apps and then use it like this:
{% load thumbs_filter %}
{{ object.image|make_thumbnail:'100x200' }}