This is a typical use-case : your site/app allows users to upload a picture. But you don’t want to store full size 8Mb picture, and still, it’s comfortable for the user to not have to manually resize the image before uploading it. The solution : resizing the image “on the fly” when receiving it on the server side.
Another use-case, also quite common : you need to generate a thumbnail for the uploaded picture. The following code will help you too.
This script is re-sizing the image only if it’s a new PicturePost (we check that the object key isn’t set).
We’re doing some calculation to get the right ratio before re-sizing the image. We can’t use the thumbnail() method because we want to resize based only on the width of the image. The thumbnail() method will resize the image based on the biggest between width and height.
We convert the image to jpeg with a 90 quality (the default is 75, 100 meaning no jpeg compression at all).
We also keep the exif information if its exists. By default, it’ll disappear, so we have to manually add them again when saving the resized file.
Once it’s resized, we save the object into the database.
from PIL import Image
from django.db import models
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.utils.six import StringIO
picture = models.ImageField(upload_to='uploads/%Y/%m/%d/')
def save(self, *args, **kwargs):
# Do extra stuff before saving
# If new post, get the picture and resize it on the fly
if self.pk is None:
# 1200px width maximum
basewidth = 1200
img = Image.open(self.picture)
# Keep the exif data
exif = None
if 'exif' in img.info:
exif = img.info['exif']
width_percent = (basewidth/float(img.size))
height_size = int((float(img.size)*float(width_percent)))
img = img.resize((basewidth, height_size), PIL.Image.ANTIALIAS)
output = StringIO()
# save the resized file to our IO ouput with the correct format and EXIF data ;-)
img.save(output, format='JPEG', exif=exif, quality=90)
img.save(output, format='JPEG', quality=90)
self.picture = InMemoryUploadedFile(output, 'ImageField', "%s.jpg" % self.picture.name, 'image/jpeg',
super(CarPost, self).save(*args, **kwargs)
You can also use the same logic to create a thumbnail of the image and store it into another ImageField field. 😉