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

前端 未结 7 1338
無奈伤痛
無奈伤痛 2020-11-27 11:58

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

相关标签:
7条回答
  • 2020-11-27 12:21

    This is 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(...)
    
    0 讨论(0)
  • 2020-11-27 12:23

    For those using django-storages/-redux to store the image file on S3, here's 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's 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()
    
    0 讨论(0)
  • 2020-11-27 12:27

    Here is an app that can do that: 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}))
        ])
    

    Make sure to pass keep_orphans=True to the field, if you want to keep old files, otherwise they are cleaned up upon replacement.

    0 讨论(0)
  • 2020-11-27 12:39

    Putting together 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())
    
    0 讨论(0)
  • 2020-11-27 12:39

    To complete for those who, like me, want to couple it with Django's FileSystemStorage: (What I do here is upload an image, resize it to 2 dimensions 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 讨论(0)
  • 2020-11-27 12:41

    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.

    0 讨论(0)
提交回复
热议问题