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

I am trying to convert an UploadedFile object to a PIL Image object to sketch it, and then convert the PIL Image object, which returns my thumbnail function back to a File object. How can i do this?

+49
python django python-imaging-library django-file-upload django-uploads
Sep 16 '10 at 2:07
source share
7 answers

The way to do this without having to write to the file system, and then return the file to memory through an open call, is to use StringIO and Django InMemoryUploadedFile. Here is a brief example of how you can do this. This assumes that you already have a thumbnail 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 work in my project right now, loading on S3 using django repositories. It took me most of the day to find the right solution here.

+95
Dec 28 '10 at 7:55
source share

I needed to do this in a few steps, the imagejpeg () image in php requires a similar process. Not to say that theres no way to store things in memory, but this method gives you a link to the file for both the original image and the thumb (this is usually a good idea if you need to go back and resize your thumb).

  • save file
  • open it from the file system using PIL,
  • save to temp directory with PIL,
  • then open the django file for this.

Model:

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

Using:

 #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) 
+13
Sep 16 '10 at 2:53 on
source share

This is the actual working example for python 3.5 and django 1.10

in views.py:

 from io import BytesIO from django.core.files.base import ContentFile from django.core.files.uploadedfile import InMemoryUploadedFile def 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(...) 
+5
Sep 26 '16 at 18:41
source share

Collection of comments and updates for Python 3+

 from io import BytesIO from django.core.files.base import ContentFile import requests # Read a file in r = request.get(image_url) image = r.content scr = Image.open(BytesIO(image)) # Perform an image operation like resize: width, height = scr.size new_width = 320 new_height = int(new_width * height / width) img = scr.resize((new_width, new_height)) # Get the Django file object thumb_io = BytesIO() img.save(thumb_io, format='JPEG') photo_smaller = ContentFile(thumb_io.getvalue()) 
+3
Mar 16 '17 at 23:05
source share

Here is an application that can do this: django-smartfields

 from django.db import models from smartfields import fields from smartfields.dependencies import FileDependency from smartfields.processors import ImageProcessor class ImageModel(models.Model): image = fields.ImageField(dependencies=[ FileDependency(processor=ImageProcessor( scale={'max_width': 150, 'max_height': 150})) ]) 

Be sure to pass keep_orphans=True in the field if you want to keep the old files, otherwise they will be cleared after replacement.

+1
Jan 31 '15 at 19:52
source share

For those using django-storages/-redux to store an image file in S3, here is the path I took (the example below creates a thumbnail of an existing image):

 from PIL import Image import StringIO from django.core.files.storage import default_storage try: # example 1: use a local file image = Image.open('my_image.jpg') # example 2: use a model ImageField image = Image.open(my_model_instance.image_field) image.thumbnail((300, 200)) except IOError: pass # handle exception thumb_buffer = StringIO.StringIO() image.save(thumb_buffer, format=image.format) s3_thumb = default_storage.open('my_new_300x200_image.jpg', 'w') s3_thumb.write(thumb_buffer.getvalue()) s3_thumb.close() 
+1
Mar 05 '16 at 3:30
source share

In conclusion, for those who, like me, want to connect it to Django FileSystemStorage : (What I am doing here is upload an image, resize it to two sizes and save both files.

utils.py

 def resize_and_save(file): size = 1024, 1024 thumbnail_size = 300, 300 uploaded_file_url = getURLforFile(file, size, MEDIA_ROOT) uploaded_thumbnail_url = getURLforFile(file, thumbnail_size, THUMBNAIL_ROOT) return [uploaded_file_url, uploaded_thumbnail_url] def getURLforFile(file, size, location): img = Image.open(file) img.thumbnail(size, Image.ANTIALIAS) thumb_io = BytesIO() img.save(thumb_io, format='JPEG') thumb_file = InMemoryUploadedFile(thumb_io, None, file.name, 'image/jpeg', thumb_io.tell, None) fs = FileSystemStorage(location=location) filename = fs.save(file.name, thumb_file) return fs.url(filename) 

In views.py

 if request.FILES: fl, thumbnail = resize_and_save(request.FILES['avatar']) #delete old profile picture before saving new one try: os.remove(BASE_DIR + user.userprofile.avatarURL) except Exception as e: pass user.userprofile.avatarURL = fl user.userprofile.thumbnailURL = thumbnail user.userprofile.save() 
0
Jun 26 '19 at 21:43
source share



All Articles