Login

Dynamic thumbnail generator

Author:
semente
Posted:
February 26, 2008
Language:
Python
Version:
1.5
Tags:
image thumbnail model imagefield
Score:
12 (after 12 ratings)

This snippet creates thumbnails on-demand from a ImageField with any size using dynamics methods, like get_photo_80x80_url or get_photo_640x480_filename, etc.

It assumes you have an ImageField in your Model called photo and have this in your models.py:

import re

from os import path
from PIL import Image

GET_THUMB_PATTERN = re.compile(r'^get_photo_(\d+)x(\d+)_(url|filename)$')

models.py example:

import re

from os import path
from PIL import Image
from django.db import models

GET_THUMB_PATTERN = re.compile(r'^get_photo_(\d+)x(\d+)_(url|filename)$')

class Photo(models.Model):
    photo = models.ImageField(upload_to='photos/%Y/%m/%d')

    <snippet here>

Example usage:

>>> photo = Photo(photo="/tmp/test.jpg")
>>> photo.save()
>>> photo.get_photo_80x80_url()
u"http://media.example.net/photos/2008/02/26/test_80x80.jpg"
>>> photo.get_photo_80x80_filename()
u"/srv/media/photos/2008/02/26/test_80x80.jpg"
>>> photo.get_photo_64x64_url()
u"http://media.example.net/photos/2008/02/26/test_64x64.jpg"
>>> photo.get_photo_64x64_filename()
u"/srv/media/photos/2008/02/26/test_64x64.jpg"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def __getattr__(self, name):
    """
    Deploys dynamic methods for on-demand thumbnails creation with any
    size.

    Syntax::

        get_photo_[WIDTH]x[HEIGHT]_[METHOD]

    Where *WIDTH* and *HEIGHT* are the pixels of the new thumbnail and
    *METHOD* can be ``url`` or ``filename``.

    Example usage::

        >>> photo = Photo(photo="/tmp/example.jpg", ...)
        >>> photo.save()
        >>> photo.get_photo_320x240_url()
        u"http://media.example.net/photos/2008/02/26/example_320x240.jpg"
        >>> photo.get_photo_320x240_filename()
        u"/srv/media/photos/2008/02/26/example_320x240.jpg"
    """
    match = re.match(GET_THUMB_PATTERN, name)
    if match is None:
        raise AttributeError, name
    width, height, method = match.groups()
    size = int(width), int(height)

    def get_photo_thumbnail_filename():
        file, ext = path.splitext(self.photo.file.name)
        return file + '_%sx%s' % size + ext

    def get_photo_thumbnail_url():
        url, ext = path.splitext(self.photo.url)
        return url + '_%sx%s' % size + ext

    thumbnail = get_photo_thumbnail_filename()
    if not path.exists(thumbnail):
        img = Image.open(self.photo.file.name)
        img.thumbnail(size, Image.ANTIALIAS)
        img.save(thumbnail)
    if method == "url":
        return get_photo_thumbnail_url
    else:
        return get_photo_thumbnail_filename

More like this

  1. ImageWithThumbsField by zenx 6 years, 7 months ago
  2. ResizeImageField by wim 4 years, 10 months ago
  3. Filter to resize a ImageField on demand by michelts 8 years, 3 months ago
  4. TestSettingsManager: temporarily change settings for tests by carljm 6 years, 11 months ago
  5. [UPDATE]Filter to resize a ImageField on demand + RATIO OPTION + CLEANUP by karlsberg 4 years, 11 months ago

Comments

semente (on February 27, 2008):

Fixed a bug:

<<<    size = width, height
>>>    size = int(width), int(height)

#

AndrewIngram (on February 27, 2008):

Nice, I can see this coming in very handy and it's a lot more straightforward than I expected it to be (a testament to the very powerful features and libraries of Python).

#

AndrewIngram (on March 1, 2008):

Is it possible to make it delete the generated images if the parent field is edited or deleted?

#

benjaoming (on August 3, 2008):

In order to automatically clean up old thumbs when a new picture is saved:

def save(self):
    # Delete thumbnails
    import glob, os
    file, ext = path.splitext(self.get_image_filename())
    pattern = file.rstrip("_") + "*x*" + ext
    thumbs = glob.glob(pattern)
    for thumb in thumbs:
        print thumb
        os.remove(thumb)

    super(GalleryImage, self).save()

#

Please login first before commenting.