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

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

不必回写到文件系统,然后通过打开的调用将文件带回内存的方式是使用StringIO和Django InMemoryUploadedFile。 这里是你如何做到这一点的快速样本。 这假设你已经有一个名为“拇指”缩略图的图像:

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

让我知道你是否需要更多的澄清。 我现在在我的项目中工作,使用django-storages上传到S3。 这花了我一天的更好的一部分,以在这里find正确的解决scheme。

我不得不在几个步骤中做到这一点,PHP中的imagejpeg()需要一个类似的过程。 不要说,没有办法保存在内存中的东西,但这种方法给你一个原始图像和拇指的文件参考(通常是一个好主意,如果你不得不回去,改变你的拇指大小)。

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

模型:

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

用法:

 #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) 

这是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(...) 

这是一个可以做到的应用程序: 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})) ]) 

如果要保留旧文件,请确保将keep_orphans=True传递给该字段,否则将在更换时清除它们。

汇总Python 3 +的注释和更新

 from io import BytesIO 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 = io.BytesIO() img.save(thumb_io, format='JPEG') photo_smaller = ContentFile(thumb_io.getvalue()) 

对于那些使用django-storages/-redux来存储S3上的图像文件,这里是我拿的path(下面的例子创build一个现有的图像缩略图):

 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()