texto - pil python
¿Cómo se convierte una ''Imagen'' de PIL en un ''Archivo'' de Django? (6)
Intento convertir un objeto UploadedFile
en un objeto PIL Image
para convertirlo en miniatura, y luego convertir el objeto PIL Image
que devuelve mi miniatura a un objeto File
. ¿Cómo puedo hacer esto?
Aquí hay una aplicación que puede hacer eso: 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}))
])
Asegúrese de pasar keep_orphans=True
al campo, si desea conservar los archivos antiguos, de lo contrario, se limpian cuando se reemplazan.
Este es un ejemplo de trabajo real para python 3.5 y django 1.10
en 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(...)
He tenido que hacer esto en unos pocos pasos, imagejpeg () en php requiere un proceso similar. No decir que no hay forma de mantener las cosas en la memoria, pero este método le da una referencia de archivo tanto de la imagen original como del pulgar (generalmente es una buena idea en caso de que tenga que retroceder y cambiar el tamaño de su pulgar).
- guarda el archivo
- abrirlo desde el sistema de archivos con PIL,
- guardar en un directorio temporal con PIL,
- luego abre como un archivo de Django para que esto funcione.
Modelo:
class YourModel(Model):
img = models.ImageField(upload_to=''photos'')
thumb = models.ImageField(upload_to=''thumbs'')
Uso:
#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)
La forma de hacerlo sin tener que volver a escribir en el sistema de archivos, y luego devolver el archivo a la memoria a través de una llamada abierta, es hacer uso de StringIO y Django InMemoryUploadedFile. Aquí hay una muestra rápida de cómo puedes hacer esto. Esto supone que ya tiene una imagen en miniatura llamada ''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.
...
Avíseme si necesita más aclaraciones. Tengo esto trabajando en mi proyecto en este momento, cargando a S3 usando django-storage. Esto me llevó la mayor parte del día encontrar adecuadamente la solución aquí.
Organizando comentarios y actualizaciones para 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())
Para aquellos que usan django-storages/-redux
para almacenar el archivo de imagen en S3, esta es la ruta que tomé (el siguiente ejemplo crea una miniatura de una imagen existente):
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()