Как преобразовать изображение PIL в файл Django?
Я пытаюсь преобразовать UploadedFile
в PIL Image
объект для эскиза его, а затем преобразовать PIL Image
объект, который моя функция миниатюр возвращает обратно в File
"объект". Как я могу это сделать?
6 ответов
способ сделать это без необходимости записи обратно в файловую систему, а затем вернуть файл в память с помощью открытого вызова-использовать 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.
...
Дайте мне знать, если вам нужно больше разъяснений. У меня это работает в моем проекте прямо сейчас, загружая в S3 с помощью django-storages. Это сделало меня лучше. часть дня, чтобы правильно найти решение здесь.
мне пришлось сделать это за несколько шагов, imagejpeg () в php требует аналогичного процесса. Не сказать, что нет способа сохранить вещи в памяти, но этот метод дает вам ссылку на файл как на исходное изображение, так и на большой палец (обычно хорошая идея, если вам нужно вернуться и изменить размер большого пальца).
- сохраните файл
- откройте его из файловой системы С помощью PIL,
- сохранить в каталог temp с PIL,
- затем откройте как файл 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.5 и Джанго 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(...)
объединение комментариев и обновлений для 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())
вот приложение, которое может это сделать:Джанго-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
в поле, если вы хотите сохранить старые файлы, иначе они очищаются после замены.
для тех, кто использует django-storages/-redux
чтобы сохранить файл изображения на S3, вот путь, который я взял (пример ниже создает эскиз существующего изображения):
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()