你如何将PIL`Image`转换为Django`File`?

oro*_*aki 50 python django django-file-upload django-uploads python-imaging-library

我正在尝试将UploadedFile一个PIL Image对象转换为缩略图,然后将Image我的缩略图函数返回的PIL 对象转换回一个File对象.我怎样才能做到这一点?

Ski*_*itz 96

不必回写文件系统,然后通过公开调用将文件带回内存的方法是使用StringIO和Django InMemoryUploadedFile.以下是有关如何执行此操作的快速示例.这假设您已经有一个名为'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.
...
Run Code Online (Sandbox Code Playgroud)

如果您需要更多说明,请与我们联系.我现在正在我的项目中工作,使用django-storage上传到S3.这花了我一天中最好的部分才能在这里找到解决方案.

  • 我发现你可以通过使用Django ContentFile类来减少工作量.在这种情况下,从django.core.files.base导入ContentFile然后你做:thumb_file = ContentFile(thumb_io.getvalue()) (25认同)
  • @madzohan你是如何让'StringIO`在Python 3中工作的?我不得不使用`BytesIO`(并且因为它没有_len()_函数,所以必须使用_tell()_来确定它的长度. (4认同)
  • @Bialecki没关系,我找到了答案.我们在保存到模型imagefield时指定名称,如下所示:mymodel.myimagefield.save(myfilename,imagecontentfile,save = True) (3认同)
  • @JohnC是的,你应该使用`BytesIO`尝试我的答案http://stackoverflow.com/a/30435175/3033586 BTW之前的评论已过时并删除 (3认同)

Lin*_*n B 13

我必须在几个步骤中执行此操作,php中的imagejpeg()需要类似的过程.不是说没有办法把东西保存在内存中,但是这个方法为你提供了原始图像和拇指的文件引用(如果你必须返回并改变你的拇指大小,通常是一个好主意).

  1. 保存文件
  2. 用PIL从文件系统打开它,
  3. 使用PIL保存到临时目录,
  4. 然后打开一个Django文件,让它工作.

模型:

class YourModel(Model):
    img = models.ImageField(upload_to='photos')
    thumb = models.ImageField(upload_to='thumbs')
Run Code Online (Sandbox Code Playgroud)

用法:

#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)
Run Code Online (Sandbox Code Playgroud)

  • 高度未经优化,您在步骤1,2,3,4中进行IO操作. (8认同)

dEl*_*Ell 6

这是python 3.5Django 1.10的实际工作示例

在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(...)
Run Code Online (Sandbox Code Playgroud)