Comment convertir une image PIL en Fichier Django?
j'essaie de convertir un UploadedFile
pour un PIL Image
objet de vignette, puis convertir le PIL Image
objet que ma vignette de la fonction retourne un File
objet. Comment puis-je faire cela?
6 réponses
la façon de faire ceci sans avoir à écrire de nouveau dans le système de fichiers, et ensuite ramener le fichier dans la mémoire via un appel ouvert, est de faire usage de StringIO et Django InMemoryUploadedFile. Voici un échantillon rapide sur comment vous pouvez le faire. Cela suppose que vous avez déjà une image appelée '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.
...
Laissez-moi savoir si vous avez besoin de plus de précisions. Je travaille sur ce projet en ce moment, je télécharge sur S3 en utilisant django-storages. Ce qui m'a pris le meilleur une partie de la journée pour bien trouver la solution ici.
j'ai dû le faire en quelques étapes, imagejpeg() en php nécessite un processus similaire. Pour ne pas dire qu'il n'y a aucun moyen de garder les choses en mémoire, mais cette méthode vous donne une référence de fichier à la fois l'image originale et le pouce (généralement une bonne idée au cas où vous devez revenir en arrière et changer la taille de votre pouce).
- enregistrez le fichier
- l'ouvrir à partir du système de fichiers avec PIL,
- " enregistrer dans un répertoire temporaire avec PIL,
- puis ouvrir en tant que Fichier Django pour ce travailler.
Modèle:
class YourModel(Model):
img = models.ImageField(upload_to='photos')
thumb = models.ImageField(upload_to='thumbs')
Utilisation:
#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)
Ceci est un exemple réel pour python 3.5 et django 1.10
dans 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(...)
Mettre ensemble des commentaires et des mises à jour pour 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())
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}))
])
assurez-vous de passer keep_orphans=True
sur le terrain, si vous voulez garder les vieux fichiers, sinon ils sont nettoyés après remplacement.
Pour ceux qui utilisent django-storages/-redux
pour stocker le fichier image sur S3, voici le chemin que j'ai pris (l'exemple ci-dessous crée une miniature d'une image existante):
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()