Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django / PIL - save thumbnail version right when image is uploaded

Tags:

This is my forms.py:

class UploadImageForm(forms.ModelForm):     class Meta:         model = UserImages         fields = ['photo'] 

and this is my models.py:

class UserImages(models.Model):     user = models.ForeignKey(User)     photo = models.ImageField(upload_to=get_file_path) 

and this is my view:

def uploadImageView(request):     if request.method == 'POST':         form = UploadImageForm(request.POST, request.FILES)         if form.is_valid():             instance = form.save(commit=False)             instance.user = request.user             instance.save()             return redirect('/')     else:         form = UploadImageForm()      return render(request, 'uploadImagePage.html', {'uploadImageForm': form}) 

But this only saves the image being uploaded. How do I save a thumbnail version of the image as well with the thumbnail version of the image having the exact same name except with the word 'thumbail' after it?

The tutorials I read said I can do

im = Image.open(infile) im.thumbnail(size, Image.ANTIALIAS) 

to get a thumbnail but in my situation, the image isn't even saved yet.

like image 736
SilentDev Avatar asked May 28 '14 21:05

SilentDev


2 Answers

Based on xjtian's answer. This works for Python 3:

import os.path from PIL import Image from io import BytesIO from django.core.files.base import ContentFile from .my_app_settings import THUMB_SIZE      class Photo(models.Model):     photo = models.ImageField(upload_to='photos')     thumbnail = models.ImageField(upload_to='thumbs', editable=False)      def save(self, *args, **kwargs):          if not self.make_thumbnail():             # set to a default thumbnail             raise Exception('Could not create thumbnail - is the file type valid?')          super(Photo, self).save(*args, **kwargs)      def make_thumbnail(self):          image = Image.open(self.photo)         image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)          thumb_name, thumb_extension = os.path.splitext(self.photo.name)         thumb_extension = thumb_extension.lower()          thumb_filename = thumb_name + '_thumb' + thumb_extension          if thumb_extension in ['.jpg', '.jpeg']:             FTYPE = 'JPEG'         elif thumb_extension == '.gif':             FTYPE = 'GIF'         elif thumb_extension == '.png':             FTYPE = 'PNG'         else:             return False    # Unrecognized file type          # Save thumbnail to in-memory file as StringIO         temp_thumb = BytesIO()         image.save(temp_thumb, FTYPE)         temp_thumb.seek(0)          # set save=False, otherwise it will run in an infinite loop         self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=False)         temp_thumb.close()          return True 
like image 146
Badjio Avatar answered Sep 17 '22 05:09

Badjio


To do this, you should add a new ImageField to your current UserImages model to hold the thumbnail, then override your the save method to create and save the thumbnail after the full image is saved.

I've adapted the following snippet of code from one of my projects that did exactly this, I'm pretty sure this will do exactly what you need it to do:

from cStringIO import StringIO import os  from django.db import models from django.core.files.base import ContentFile from django.core.files.storage import default_storage as storage  from PIL import Image  # Thumbnail size tuple defined in an app-specific settings module - e.g. (400, 400) from app.settings import THUMB_SIZE  class Photo(models.Model):     """     Photo model with automatically generated thumbnail.     """     photo = models.ImageField(upload_to='photos')     thumbnail = models.ImageField(upload_to='thumbs', editable=False)      def save(self, *args, **kwargs):         """         Make and save the thumbnail for the photo here.         """         super(Photo, self).save(*args, **kwargs)         if not self.make_thumbnail():             raise Exception('Could not create thumbnail - is the file type valid?')      def make_thumbnail(self):         """         Create and save the thumbnail for the photo (simple resize with PIL).         """         fh = storage.open(self.photo.name, 'r')         try:             image = Image.open(fh)         except:             return False          image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)         fh.close()          # Path to save to, name, and extension         thumb_name, thumb_extension = os.path.splitext(self.photo.name)         thumb_extension = thumb_extension.lower()          thumb_filename = thumb_name + '_thumb' + thumb_extension          if thumb_extension in ['.jpg', '.jpeg']:             FTYPE = 'JPEG'         elif thumb_extension == '.gif':             FTYPE = 'GIF'         elif thumb_extension == '.png':             FTYPE = 'PNG'         else:             return False    # Unrecognized file type          # Save thumbnail to in-memory file as StringIO         temp_thumb = StringIO()         image.save(temp_thumb, FTYPE)         temp_thumb.seek(0)          # Load a ContentFile into the thumbnail field so it gets saved         self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=True)         temp_thumb.close()          return True 
like image 23
xjtian Avatar answered Sep 17 '22 05:09

xjtian