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

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


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 StringIOfrom 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 herethumb_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.


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 codeuploaded = request.FILES['photo']from django.core.files.base import ContentFilefile_content = ContentFile(uploaded.read())new_file = YourModel() #1 - get it into the DB and file system so we know the real pathnew_file.img.save(str(new_file.id) + '.jpg', file_content)new_file.save()from PIL import Imageimport os.path#2, open it from the location django stuck itthumb = Image.open(new_file.img.path)thumb.thumbnail(100, 100)#make tmp filename based on id of the modelfilename = str(new_file.id)#3. save the thumbnail to a temp dirtemp_image = open(os.path.join('/tmp',filename), 'w')thumb.save(temp_image, 'JPEG')#4. read the temp file back into a Filefrom django.core.files import Filethumb_data = open(os.path.join('/tmp',filename), 'r')thumb_file = File(thumb_data)new_file.thumb.save(str(new_file.id) + '.jpg', thumb_file)


This is actual working example for python 3.5 and django 1.10

in views.py:

from io import BytesIOfrom django.core.files.base import ContentFilefrom django.core.files.uploadedfile import InMemoryUploadedFiledef pill(image_io):    im = Image.open(image_io)    ltrb_border = (0, 0, 0, 10)    im_with_border = ImageOps.expand(im, border=ltrb_border, fill='white')    buffer = BytesIO()    im_with_border.save(fp=buffer, format='JPEG')    buff_val = buffer.getvalue()    return ContentFile(buff_val)def save_img(request)    if request.POST:       new_record = AddNewRecordForm(request.POST, request.FILES)       pillow_image = pill(request.FILES['image'])       image_file = InMemoryUploadedFile(pillow_image, None, 'foo.jpg', 'image/jpeg', pillow_image.tell, None)       request.FILES['image'] = image_file  # really need rewrite img in POST for success form validation       new_record.image = request.FILES['image']       new_record.save()       return redirect(...)