Login

Yet Another Image Resizer

Author:
stephen_mcd
Posted:
February 25, 2010
Language:
Python
Version:
1.1
Score:
2 (after 2 ratings)

There's a whole range of examples online for resizing images in Django some of which are incredibly comprehensive with a wide variety of options. Here's my take on the task that serves as a simple drop in for when you don't want to include a separate app.

  • Only generates the resized image when first requested.
  • Handles maintaining proportions when specifying only a width or a height.
  • Makes use of PIL.ImageOps.fit for cropping without reinventing the wheel.
 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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
"""
A simple drop-in image resizing templatetag.

* Only generates the resized image when first requested.
* Handles maintaining proportions when specifying only a width or a height.
* Makes use of PIL.ImageOps.fit for cropping without reinventing the wheel.

Usage:

Resize to 200px wide maintaining ratio: {% thumbnail path_to_image 200 0 %}
Resize to 200px high maintaining ratio: {% thumbnail path_to_image 0 200 %}
Resize and crop to 200x200px {% thumbnail path_to_image 200 200 %}

Credits:
--------

Stephen McDonald <[email protected]>

License:
--------

Creative Commons Attribution-Share Alike 3.0 License
http://creativecommons.org/licenses/by-sa/3.0/

When attributing this work, you must maintain the Credits
paragraph above.
"""

import os

from django import template
from django.conf import settings


register = template.Library()


@register.simple_tag
def thumbnail(image_url, width, height):
    """
    Given the url to an image, resizes the image using the given width and 
    height on the first time it is requested, and returns the url to the new 
    resized image. If width or height are zero then the original ratio is 
    maintained.
    """
    
    image_url = unicode(image_url)
    image_path = os.path.join(settings.MEDIA_ROOT, image_url)
    image_dir, image_name = os.path.split(image_path)
    thumb_name = "%s-%sx%s.jpg" % (os.path.splitext(image_name)[0], width, height)
    thumb_path = os.path.join(image_dir, thumb_name)
    thumb_url = "%s/%s" % (os.path.dirname(image_url), thumb_name)

    # abort if thumbnail exists, original image doesn't exist, invalid width or 
    # height are given, or PIL not installed
    if not image_url:
        return ""
    if os.path.exists(thumb_path):
        return thumb_url
    try:
        width = int(width)
        height = int(height)
    except ValueError:
        return image_url
    if not os.path.exists(image_path) or (width == 0 and height == 0):
        return image_url
    try:
        from PIL import Image, ImageOps
    except ImportError:
        return image_url

    # open image, determine ratio if required and resize/crop/save
    image = Image.open(image_path)
    if width == 0:
        width = image.size[0] * height / image.size[1]
    elif height == 0:
        height = image.size[1] * width / image.size[0]
    if image.mode not in ("L", "RGB"):
        image = image.convert("RGB")
    try:
        image = ImageOps.fit(image, (width, height), Image.ANTIALIAS).save(
            thumb_path, "JPEG", quality=100)
    except:
        return image_url
    return thumb_url

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
  5. Help text hyperlinks by sa2812 1 year, 8 months ago

Comments

cocbiz (on July 13, 2011):

+1 for ImageOps.fit

#

jperals (on January 4, 2012):

Maybe an alternative would be to use as a parameter the image itself, instead of its URL.

This way, you could easily access its path as well as its URL or whatever, saving some of these string manipulations.

#

jperals (on January 4, 2012):

Oh, I guess that if we are calling the function from a templatetag, we can only pass strings?

#

Please login first before commenting.