Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you convert a PIL `Image` to a Django `File`?

I'm trying to convert an UploadedFile to a PIL Image object to thumbnail it, and then convert the PIL Image object that my thumbnail function returns back into a File object. How can I do this?

like image 478
orokusaki Avatar asked Sep 16 '10 02:09

orokusaki


People also ask

How do I Pil an image?

Image. open() Opens and identifies the given image file. This is a lazy operation; this function identifies the file, but the file remains open and the actual image data is not read from the file until you try to process the data (or call the load() method).

Where are images stored in Django project?

In Django, a default database is automatically created for you. All you have to do is add the tables called models. The upload_to tells Django to store the photo in a directory called pics under the media directory. The list_display list tells Django admin to display its contents in the admin dashboard.


2 Answers

The way to do this without having to write back to the filesystem, and then bring the file back into memory via an open call, is to make use of StringIO and Django InMemoryUploadedFile. Here is a quick sample on how you might do this. This assumes that you already have a thumbnailed image named 'thumb':

import StringIO  from django.core.files.uploadedfile import InMemoryUploadedFile  # Create a file-like object to write thumb data (thumb data previously created # using PIL, and stored in variable 'thumb') thumb_io = StringIO.StringIO() thumb.save(thumb_io, format='JPEG')  # Create a new Django file-like object to be used in models as ImageField using # InMemoryUploadedFile.  If you look at the source in Django, a # SimpleUploadedFile is essentially instantiated similarly to what is shown here thumb_file = InMemoryUploadedFile(thumb_io, None, 'foo.jpg', 'image/jpeg',                                   thumb_io.len, None)  # Once you have a Django file-like object, you may assign it to your ImageField # and save. ... 

Let me know if you need more clarification. I have this working in my project right now, uploading to S3 using django-storages. This took me the better part of a day to properly find the solution here.

like image 63
Skitz Avatar answered Oct 07 '22 17:10

Skitz


I've had to do this in a few steps, imagejpeg() in php requires a similar process. Not to say theres no way to keep things in memory, but this method gives you a file reference to both the original image and thumb (usually a good idea in case you have to go back and change your thumb size).

  1. save the file
  2. open it from filesystem with PIL,
  3. save to a temp directory with PIL,
  4. then open as a Django file for this to work.

Model:

class YourModel(Model):     img = models.ImageField(upload_to='photos')     thumb = models.ImageField(upload_to='thumbs') 

Usage:

#in upload code uploaded = request.FILES['photo'] from django.core.files.base import ContentFile file_content = ContentFile(uploaded.read()) new_file = YourModel()  #1 - get it into the DB and file system so we know the real path new_file.img.save(str(new_file.id) + '.jpg', file_content) new_file.save()  from PIL import Image import os.path  #2, open it from the location django stuck it thumb = Image.open(new_file.img.path) thumb.thumbnail(100, 100)  #make tmp filename based on id of the model filename = str(new_file.id)  #3. save the thumbnail to a temp dir  temp_image = open(os.path.join('/tmp',filename), 'w') thumb.save(temp_image, 'JPEG')  #4. read the temp file back into a File from django.core.files import File thumb_data = open(os.path.join('/tmp',filename), 'r') thumb_file = File(thumb_data)  new_file.thumb.save(str(new_file.id) + '.jpg', thumb_file) 
like image 31
Lincoln B Avatar answered Oct 07 '22 16:10

Lincoln B