Bildgröße anpassen zu speichern
-
05-07-2019 - |
Frage
Wie kann ich leicht ein Bild Größe ändern, nachdem es in Django hochgeladen wurde? Ich verwende Django 1.0.2 und ich habe PIL installiert.
Ich dachte über das Überschreiben die save () Methode des Modells es um die Größe, aber ich weiß wirklich nicht, wie es zu starten und außer Kraft setzen.
Kann mir jemand in die richtige Richtung? Danke: -)
@ Guðmundur H: Das wird nicht funktionieren, weil das django-stdimage Paket unter Windows funktioniert nicht: - (
Lösung
Andere Tipps
Ich empfehle, mit StdImageField von django-stdimage , sollte es alle die schmutzige Arbeit für Sie erledigen . Es ist einfach zu bedienen, einfach die Dimensionen des skalierte Bildes in der Felddefinition angeben:
class MyModel(models.Model):
image = StdImageField(upload_to='path/to/img', size=(640, 480))
Überprüfen Sie die Dokumentation - es auch Thumbnails tun können,
.Ich benutze diesen Code hochgeladene Bilder zu handhaben, die Größe ändern auf Speicher (whithout sie dauerhaft auf der Festplatte zu speichern) und dann den Daumen auf einem Django Imagefield zu speichern. Hoffe, dass helfen kann.
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()
Ich empfehle den SORL-Thumbnail App für Bild Handhabung einfach und transparent Größe ändern. Es geht in jedem einzelnen Django Projekt, das ich starten.
Ich weiß, das ist alt, aber für jemand auf sie stolpern, es ist ein Paket, django-thumbs
unter Django-Daumen - Easy leistungsstarke Thumbnails für Django integriert mit StorageBackend , die Sie Thumbnails in den Größen angeben, oder keine, wenn Sie nicht automatisch erzeugt. Anschließend rufen Sie das Miniaturbild, das Sie mit den Dimensionen wollen Sie wollen.
Zum Beispiel, wenn Sie ein Bild wollen Thumbnails von 64x64 haben und 128x128, importieren Sie einfach thumbs.models.ImageWithThumbsField
, und es anstelle von ImageField
verwenden. Fügen Sie einen Parameter sizes=((64,64),(128,128))
auf die Felddefinition, dann aus Ihrer Vorlage können Sie anrufen:
{{ ClassName.field_name.url_64x64 }}
und
{{ ClassName.field_name.url_128x128 }}
die Thumbnails angezeigt werden soll. Voila! Die ganze Arbeit ist für Sie in diesem Paket durchgeführt.
Hier ist eine komplette Lösung für ya ein Formular. Ich benutzte Admin-Ansichten für diese:
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
Ihr Inventar Modell sieht wie folgt aus:
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)
....
I beendet die Funktion des Modells speichern überschrieben wird stattdessen das Foto und einen Daumen zu speichern, anstatt nur das Foto Größe ändern:
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()
Beide arbeiten toll, aber je nachdem, was Sie tun möchten:)
Wenn Sie Django Ruhe Framework verwenden, könnte dies für die Verwendung:
Erste Funktion definieren, um Bild zu komprimieren und die Größe
def compress_image(photo):
# start compressing image
image_temporary = Image.open(photo)
output_io_stream = BytesIO()
image_temporary.thumbnail((1250, 1250), Image.ANTIALIAS)
# change orientation if necessary
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = dict(image_temporary._getexif().items())
# noinspection PyUnboundLocalVariable
if exif.get(orientation) == 3:
image_temporary = image_temporary.rotate(180, expand=True)
elif exif.get(orientation) == 6:
image_temporary = image_temporary.rotate(270, expand=True)
elif exif.get(orientation) == 8:
image_temporary = image_temporary.rotate(90, expand=True)
# saving output
image_temporary.save(output_io_stream, format='JPEG', quality=75, optimize=True, progressive=True)
output_io_stream.seek(0)
photo = InMemoryUploadedFile(output_io_stream, 'ImageField', "%s.jpg" % photo.name.split('.')[0],
'image/jpeg', getsizeof(output_io_stream), None)
return photo
Zweitens, jetzt können Sie die Funktion in Serializer verwenden:
class SomeSerializer(serializers.ModelSerializer):
def update(self, instance, validated_data):
# сжимаем рисунок
if 'photo' in validated_data:
validated_data.update({'photo': compress_image(validated_data['photo'])})
return super(SomeSerializer, self).update(instance, validated_data)
def create(self, validated_data):
# сжимаем рисунок
if 'photo' in validated_data:
validated_data.update({'photo': compress_image(validated_data['photo'])})
return super(SomeSerializer, self).create(validated_data)