如何在保存之前使用PIL调整上传文件的大小?
我知道这个问题很简单,而且已经有人回答过很多次了,但我就是搞不明白。有没有办法在把图片保存到硬盘之前先调整大小和裁剪?我找到的所有解决方案都是先保存图片,然后再调整大小,最后再保存一次。我能不能直接这样做呢?
# extending form's save() method
def save(self):
import Image as pil
# if avatar is uploaded, we need to scale it
if self.files['avatar']:
img = pil.open(self.files['avatar'])
img.thumbnail((150, 150), pil.ANTIALIAS)
# ???
# self.files['avatar'] is InMemoryUpladedFile
# how do I replace self.files['avatar'] with my new scaled image here?
# ???
super(UserForm, self).save()
2 个回答
0
我对PIL不太熟悉,但从文档上看,你可以把文件对象作为“file”参数传给“open”函数。
Django中的request.FILES
存储的是UploadedFile对象——这是一个简单的包装器,用来处理上传的文件(这些文件可以存储在内存中或者临时文件里)。这个对象支持读取、定位和获取当前位置等操作,所以可以直接传给PIL的“open”函数。
6
我找到了这个问题的解决办法。你只需要把修改过的文件保存为 StringIO
,然后再从这个文件创建一个新的 InMemoryUploadedFile
。下面是完整的解决方案:
def save(self):
import Image as pil
import StringIO, time, os.path
from django.core.files.uploadedfile import InMemoryUploadedFile
# if avatar is uploaded, we need to scale it
if self.files['avatar']:
# opening file as PIL instance
img = pil.open(self.files['avatar'])
# modifying it
img.thumbnail((150, 150), pil.ANTIALIAS)
# saving it to memory
thumb_io = StringIO.StringIO()
img.save(thumb_io, self.files['avatar'].content_type.split('/')[-1].upper())
# generating name for the new file
new_file_name = str(self.instance.id) +'_avatar_' +\
str(int(time.time())) + \
os.path.splitext(self.instance.avatar.name)[1]
# creating new InMemoryUploadedFile() based on the modified file
file = InMemoryUploadedFile(thumb_io,
u"avatar", # important to specify field name here
new_file_name,
self.files['avatar'].content_type,
thumb_io.len,
None)
# and finally, replacing original InMemoryUploadedFile() with modified one
self.instance.avatar = file
# now, when form will be saved, it will use the modified file, instead of the original
super(UserForm, self).save()