Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image resizing with django?

I'm new to Django (and Python) and I have been trying to work out a few things myself, before jumping into using other people's apps. I'm having trouble understanding where things 'fit' in the Django (or Python's) way of doing things. What I'm trying to work out is how to resize an image, once it's been uploaded. I have my model setup nicely and plugged into the admin, and the image uploads fine to the directory:

from django.db import models

# This is to list all the countries
# For starters though, this will be just United Kingdom (GB)
class Country(models.Model):
    name = models.CharField(max_length=120, help_text="Full name of country")
    code = models.CharField(max_length=2, help_text="This is the ISO 3166 2-letter country code (see: http://www.theodora.com/country_digraphs.html)")
    flag = models.ImageField(upload_to="images/uploaded/country/", max_length=150, help_text="The flag image of the country.", blank=True)

    class Meta:
        verbose_name_plural = "Countries"

    def __unicode__(self):
        return self.name

The thing I'm now having trouble with is taking that file and making a new file into a thumbnail. Like I say, I'd like to know how to do it without using others' apps (for now). I have got this code from DjangoSnippets:

from PIL import Image
import os.path
import StringIO

def thumbnail(filename, size=(50, 50), output_filename=None):
    image = Image.open(filename)
    if image.mode not in ('L', 'RGB'):
        image = image.convert('RGB')
    image = image.resize(size, Image.ANTIALIAS)

    # get the thumbnail data in memory.
    if not output_filename:
        output_filename = get_default_thumbnail_filename(filename)
    image.save(output_filename, image.format) 
    return output_filename

def thumbnail_string(buf, size=(50, 50)):
    f = StringIO.StringIO(buf)
    image = Image.open(f)
    if image.mode not in ('L', 'RGB'):
        image = image.convert('RGB')
    image = image.resize(size, Image.ANTIALIAS)
    o = StringIO.StringIO()
    image.save(o, "JPEG")
    return o.getvalue()

def get_default_thumbnail_filename(filename):
    path, ext = os.path.splitext(filename)
    return path + '.thumb.jpg'

...but this has ultimately confused me... As I don't know how this 'fits in' to my Django app? And really, is it the best solution for simply making a thumbnail of an image that has been successfully uploaded? Can anyone possibly show me a good, solid, decent way that a beginner like me can learn to do this properly? As in, knowing where to put that sort of code (models.py? forms.py? ...) and how it would work in context? ... I just need a bit of help understanding and working this problem out.

Thank you!

like image 978
littlejim84 Avatar asked Jul 22 '09 12:07

littlejim84


People also ask

How do you change the size of an image in Python?

To resize an image, you call the resize() method on it, passing in a two-integer tuple argument representing the width and height of the resized image. The function doesn't modify the used image; it instead returns another Image with the new dimensions.

How do I resize an image in node?

NodeJS – Resize() is an inbuilt function that is used to resize the images to the desired size. We can use resize to set the height and width using a 2-pass bilinear algorithm. It can resize an image into any size as declared by the user. We can take input from the user or resize it into fixed Width*Height size.


2 Answers

If it's OK for you, there is a Django application ready, doing exactly what you want: https://github.com/sorl/sorl-thumbnail

like image 113
leafnode Avatar answered Oct 25 '22 13:10

leafnode


This is what I use in my models to save a new thumbnail if the uploaded image has changed. It's based of another DjangoSnippet but it I can't remember who wrote the orginal - if you know please add a comment so that I can credit them.

from PIL import Image
from django.db import models
from django.contrib.auth.models import User

import os
import settings

class Photo_Ex(models.Model):
    user = models.ForeignKey(User, blank=True, null=True)    
    photo = models.ImageField(upload_to='photos')
    thumbnail = models.ImageField(upload_to='profile_thumb', blank=True,
                              null=True, editable=False)

    def save(self, *args, **kwargs):
        size = (256,256)
        if not self.id and not self.photo:
            return

        try:
            old_obj = Photo_Ex.objects.get(pk=self.pk)
            old_path = old_obj.photo.path
        except:
            pass

        thumb_update = False
        if self.thumbnail:
            try:
                statinfo1 = os.stat(self.photo.path)
                statinfo2 = os.stat(self.thumbnail.path)
                if statinfo1 > statinfo2:
                    thumb_update = True
            except:
                thumb_update = True

        pw = self.photo.width
        ph = self.photo.height
        nw = size[0]
        nh = size[1]

        if self.photo and not self.thumbnail or thumb_update:
            # only do this if the image needs resizing
            if (pw, ph) != (nw, nh):
                filename = str(self.photo.path)
                image = Image.open(filename)
                pr = float(pw) / float(ph)
                nr = float(nw) / float(nh)

                if image.mode not in ('L', 'RGB'):
                    image = image.convert('RGB')

                if pr > nr:
                    # photo 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:
                    # photo 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:
                    # photo aspect matches the destination ratio
                    image = image.resize(size, Image.ANTIALIAS)

            image.save(self.get_thumbnail_path())
            (a, b) = os.path.split(self.photo.name)
            self.thumbnail = a + '/thumbs/' + b
            super(Photo_Ex, self).save()
            try:
                os.remove(old_path)
                os.remove(self.get_old_thumbnail_path(old_path))
            except:
                pass

    def get_thumbnail_path(self):
        (head, tail) = os.path.split(self.photo.path)
        if not os.path.isdir(head + '/thumbs'):
            os.mkdir(head + '/thumbs')
        return head + '/thumbs/' + tail

    def get_old_thumbnail_path(self, old_photo_path):
        (head, tail) = os.path.split(old_photo_path)
        return head + '/thumbs/' + tail   
like image 29
Frozenskys Avatar answered Oct 25 '22 11:10

Frozenskys