template - inclusion tags django
cambiar el tamaƱo de la imagen al guardar (6)
Debe usar un método para manejar el archivo cargado, como se demuestra en la documentación de Django .
En este método, podría concatenar los fragmentos en una variable (en lugar de escribirlos en el disco directamente), crear una imagen PIL a partir de esa variable, cambiar el tamaño de la imagen y guardarla en el disco.
En PIL, debe mirar Image.fromstring
y Image.resize
.
¿Cómo puedo cambiar el tamaño de una imagen fácilmente después de que se cargó en Django? Estoy usando Django 1.0.2 y he instalado PIL.
Estaba pensando en anular el método save () del Modelo para cambiar su tamaño, pero realmente no sé cómo comenzar y anularlo.
¿Alguien me puede apuntar en la dirección correcta? Gracias :-)
@ Guðmundur H: Esto no funcionará porque el paquete django-stdimage no funciona en Windows :-(
Recomiendo encarecidamente la aplicación de miniatura Sorl para manejar el cambio de tamaño de imagen de forma fácil y transparente. Va en cada proyecto de Django que empiezo.
Sé que esto es viejo, pero para cualquiera que lo encuentre, hay un paquete, django-thumbs
en Django-thumbs: miniaturas fáciles y potentes para Django integradas con StorageBackend , que genera miniaturas automáticamente en los tamaños que especifique, o ninguna si no lo hace t. A continuación, llame a la miniatura que desee con las dimensiones que desee.
Por ejemplo, si desea que una imagen tenga miniaturas de 64x64 y 128x128, simplemente importe thumbs.models.ImageWithThumbsField
y thumbs.models.ImageWithThumbsField
en lugar de ImageField
. Agregue un sizes=((64,64),(128,128))
parámetro sizes=((64,64),(128,128))
a la definición de campo, luego de su plantilla puede llamar:
{{ ClassName.field_name.url_64x64 }}
y
{{ ClassName.field_name.url_128x128 }}
para mostrar las miniaturas Voila! Todo el trabajo se hace en este paquete para usted.
Utilizo este código para manejar las imágenes cargadas, cambiar su tamaño en la memoria (sin guardarlas permanentemente en el disco) y luego guardar el pulgar en un Django ImageField. Hope puede ayudar.
def handle_uploaded_image(i):
import StringIO
from PIL import Image, ImageOps
import os
from django.core.files import File
# read image from InMemoryUploadedFile
image_str = “”
for c in i.chunks():
image_str += c
# create PIL Image instance
imagefile = StringIO.StringIO(image_str)
image = Image.open(imagefile)
# if not RGB, convert
if image.mode not in (“L”, “RGB”):
image = image.convert(“RGB”)
#define file output dimensions (ex 60x60)
x = 130
y = 130
#get orginal image ratio
img_ratio = float(image.size[0]) / image.size[1]
# resize but constrain proportions?
if x==0.0:
x = y * img_ratio
elif y==0.0:
y = x / img_ratio
# output file ratio
resize_ratio = float(x) / y
x = int(x); y = int(y)
# get output with and height to do the first crop
if(img_ratio > resize_ratio):
output_width = x * image.size[1] / y
output_height = image.size[1]
originX = image.size[0] / 2 - output_width / 2
originY = 0
else:
output_width = image.size[0]
output_height = y * image.size[0] / x
originX = 0
originY = image.size[1] / 2 - output_height / 2
#crop
cropBox = (originX, originY, originX + output_width, originY + output_height)
image = image.crop(cropBox)
# resize (doing a thumb)
image.thumbnail([x, y], Image.ANTIALIAS)
# re-initialize imageFile and set a hash (unique filename)
imagefile = StringIO.StringIO()
filename = hashlib.md5(imagefile.getvalue()).hexdigest()+’.jpg’
#save to disk
imagefile = open(os.path.join(‘/tmp’,filename), ‘w’)
image.save(imagefile,’JPEG’, quality=90)
imagefile = open(os.path.join(‘/tmp’,filename), ‘r’)
content = File(imagefile)
return (filename, content)
#views.py
form = YourModelForm(request.POST, request.FILES, instance=profile)
if form.is_valid():
ob = form.save(commit=False)
try:
t = handle_uploaded_image(request.FILES[‘icon’])
ob.image.save(t[0],t[1])
except KeyError:
ob.save()
Recomiendo usar StdImageField desde django-stdimage , debería manejar todo el trabajo sucio para usted. Es fácil de usar, solo especifica las dimensiones de la imagen redimensionada en la definición de campo:
class MyModel(models.Model):
image = StdImageField(upload_to=''path/to/img'', size=(640, 480))
Mira los documentos, también puede hacer miniaturas.
Aquí hay una solución completa para ti usando un formulario. Utilicé vistas de administrador para esto:
class MyInventoryItemForm(forms.ModelForm):
class Meta:
model = InventoryItem
exclude = [''thumbnail'', ''price'', ''active'']
def clean_photo(self):
import StringIO
image_field = self.cleaned_data[''photo'']
photo_new = StringIO.StringIO(image_field.read())
try:
from PIL import Image, ImageOps
except ImportError:
import Image
import ImageOps
image = Image.open(photo_new)
# ImageOps compatible mode
if image.mode not in ("L", "RGB"):
image = image.convert("RGB")
image.thumbnail((200, 200), Image.ANTIALIAS)
image_file = StringIO.StringIO()
image.save(image_file, ''png'')
image_field.file = image_file
return image_field
Mi modelo de inventario se ve así:
class InventoryItem(models.Model):
class Meta:
ordering = [''name'']
verbose_name_plural = "Items"
def get_absolute_url(self):
return "/products/{0}/".format(self.slug)
def get_file_path(instance, filename):
if InventoryItem.objects.filter(pk=instance.pk):
cur_inventory = InventoryItem.objects.get(pk=instance.pk)
if cur_inventory.photo:
old_filename = str(cur_inventory.photo)
os.remove(os.path.join(MEDIA_ROOT, old_filename))
ext = filename.split(''.'')[-1]
filename = "{0}.{1}".format(uuid.uuid4(), ext)
return os.path.join(''inventory'', filename)
#return os.path.join(filename)
def admin_image(self):
return ''<img height="50px" src="{0}/{1}"/>''.format(MEDIA_URL, self.photo)
admin_image.allow_tags = True
photo = models.ImageField(_(''Image''), upload_to=get_file_path, storage=fs, blank=False, null=False)
thumbnail = models.ImageField(_(''Thumbnail''), upload_to="thumbnails/", storage=fs, blank=True, null=True)
....
Terminé sobreescribiendo la función de guardar del modelo para guardar la foto y un pulgar en lugar de simplemente cambiar el tamaño de la foto:
def save(self):
# Save this photo instance first
super(InventoryItem, self).save()
from PIL import Image
from cStringIO import StringIO
from django.core.files.uploadedfile import SimpleUploadedFile
# Set our max thumbnail size in a tuple (max width, max height)
THUMBNAIL_SIZE = (200, 200)
# Open original photo which we want to thumbnail using PIL''s Image object
image = Image.open(os.path.join(MEDIA_ROOT, self.photo.name))
if image.mode not in (''L'', ''RGB''):
image = image.convert(''RGB'')
image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS)
# Save the thumbnail
temp_handle = StringIO()
image.save(temp_handle, ''png'') # image stored to stringIO
temp_handle.seek(0) # sets position of file to 0
# Save to the thumbnail field
suf = SimpleUploadedFile(os.path.split(self.photo.name)[-1],
temp_handle.read(), content_type=''image/png'') # reads in the file to save it
self.thumbnail.save(suf.name+''.png'', suf, save=False)
#Save this photo instance again to save the thumbnail
super(InventoryItem, self).save()
Ambos funcionan bien, dependiendo de lo que quieras hacer :)