Update: There are quite some interesting projects to create thumbnails and provide storage access. django-imagekit, django-thumbs, sorl-thumbnail, django-storages etc. Check them out!!

It’s been a while since I blogged and just wanted to share a quick snippet I wrote to create avatar/profile image for user’s. There are quite some reusable apps like django-avatar which you can hook up in no time.

Recently in one my projects, I had a different situation where profile picture was part of a Model (Role). So I had to develop a solution which creates a thumbnail for a uploaded picture and upload it to S3.

To start you just need a simple ImageField/FileField upload form. Follow this tutorial to create the form and the associated view.

I will continue where that tutorial left off. So we need to write the method ‘handle_uploaded_file’ which handles the image upload. You can add some validations to the form to check if image is less than certain size (like 700KB) etc. I will leave that you. In the method ‘handle_uploaded_file’ we need to first create a thumbnail of the uploaded picture.

I am passing two parameters to the function ‘handle_uploaded_file’ one being the user_id of the user who uploaded the picture and second being the image it self. I wanted to name the picture as <user_id_125>.jpg where 125 being resolution of the picture.

Now to create a simple thumbnail you can use the wonderful PIL(Python Imaging Library) thumbnail function. But I wanted to create a square thumbnail irrespective of the image orientation. To achieve this we need to cut the largest square out of the uploaded picture.

def handle_uploaded_file(user_id, file):
     im_orig = Image.open(picture_file)
     ## First make the image a square. Crop it.
     imo = do_rotate_on_exif(im_orig)
     width, height = imo.size

     if width > height:
         delta = width - height
         left = int(delta/2)
         upper = 0
         right = height + left
         lower = height
     else:
        delta = height - width
        left = int(delta)/2
        upper = 0
        right = width
        lower = width + upper

     im = imo.crop((left, upper, right, lower))

def do_rotate_on_exif(im_orig):
    try:
        orientation = im_orig._getexif()[274]        
        if orientation == 3:
            im = im_orig.rotate(180)
        elif orientation == 6:
            im = im_orig.rotate(-90)
        elif orientation == 8:
            im = im_orig.rotate(90)
        return im
    except:
        return im_orig

So the above snippet cuts out the largest square from any picture. Now on to resize step.

THUMBNAIL_SIZE = 70, 70

def create_thumbnail(image_object, user_id):
    image_object.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS)
    image_object.save(profile_image_path + str(user_id) + "_70.jpg", "JPEG")
    filedata = open(profile_image_path + str(user_id) + "_70.jpg", 'rb').read()
    conn.put(BUCKET_NAME, 'images/provider/' + str(user_id)+'_70.jpg',
    S3.S3Object(filedata), {'x-amz-acl': 'public-read', 
   'Content-Type': 'image/jpeg'})

This creates the thumbnail of the desired size and writes to the localfile system and immediately reads the image and uploads to S3. Note you need python S3 bindings. Get them here.

profile_image_path = settings.MEDIA_ROOT + '/images/provider/'
AWS_ACCESS_KEY_ID = 'YOUR_AWS_KEY'
AWS_SECRET_ACCESS_KEY = 'YOUR_AWS_SECRET'
BUCKET_NAME = settings.AMAZON_MEDIA_BUCKET
conn = S3.AWSAuthConnection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)

Sweet! is n’t it. You can even give the user option to delete his picture. It’s as easy as

conn.delete(BUCKET_NAME, 'images/provider/' + str(user_id)+'_70.jpg')

Hope that helps!! Grab all code here.