7👍
✅
Final solution, working for me :
from django.core.files.uploadedfile import InMemoryUploadedFile
from PIL import Image as Img
import StringIO
from django.db.models.signals import post_delete
from django.dispatch import receiver
Class Mymodel(models.Model):
photo= models.ImageField(upload_to="photo/", blank=True, null=True)
def save(self, *args, **kwargs):
width = 500
height = 500
size = (width,height)
isSame = False
if self.photo:
try:
this = Mymodel.objects.get(id=self.id)
if this.photo==self.photo :
isSame= True
except: pass # when new photo then we do nothing, normal case
image = Img.open(StringIO.StringIO(self.photo.read()))
(imw, imh) = image.size
if (imw>width) or (imh>height) :
image.thumbnail(size, Img.ANTIALIAS)
#If RGBA, convert transparency
if image.mode == "RGBA":
image.load()
background = Img.new("RGB", image.size, (255, 255, 255))
background.paste(image, mask=image.split()[3]) # 3 is the alpha channel
image=background
output = StringIO.StringIO()
image.save(output, format='JPEG', quality=60)
output.seek(0)
self.photo = InMemoryUploadedFile(output,'ImageField', "%s.jpg" %self.photo.name.split('.')[0], 'image/jpeg', output.len, None)
try:
this = Mymodel.objects.get(id=self.id)
if this.photo==self.photo or isSame :
self.photo=this.photo
else :
this.photo.delete(save=False)
except: pass # when new photo then we do nothing, normal case
super(Mymodel, self).save(*args, **kwargs)
@receiver(post_delete, sender=Mymodel)
def photo_post_delete_handler(sender, **kwargs):
instance = kwargs['instance']
storage, path = instance.photo.storage, instance.photo.path
if (path!='.') and (path!='/') and (path!='photo/') and (path!='photo/.'):
storage.delete(path)
Hope it can help somebody 😉
1👍
This Builds on Ralph’s answer worked for me for python 3 and django 2
first you must import io:
from io import BytesIO
To resize and add white background where necessary:
def resize_with_white_background(pil_image: Image.Image, desired_width, desired_height):
img_copy = pil_image.copy()
# get proportioned image ie (if image is 200X600 and trying to resize to 100X200
# thumbnail will NOT do this but resize to keep the ratio so it would be 67x200 to maintain the ratio (uses the larger)
# img_copy changed in place (does not create new image)
img_copy.thumbnail((desired_width, desired_height), Image.ANTIALIAS)
# create white background
background = Image.new('RGB', (desired_width, desired_height), (255,255,255))
pixels_to_move_left = int((background.width - img_copy.width) * 0.50) # centered horizontally
pixels_to_move_down = int((background.height - img_copy.height) * 0.50) # centered vertically
# paste image into white background box argument tells where to paste
background.paste(img_copy, box=(pixels_to_move_left, pixels_to_move_down))
return background # this will return the background with img_copy pasted in and will be resized to fit your desired size
To set the resized image to and ImageField create a method in your model:
def set_image(self, desired_width, desired_height):
try:
this = MyModel.objects.get(id=self.id)
except MyModel.DoesNotExist:
pass
else:
# will not resize or set to new image (this avoids setting image every single time you edit and save
if this.image == self.image and (self.image.width, self.image.height) == (desired_width, desired_height):
return
im = Image.open(BytesIO(self.image.read()))
resized_image = resize_with_white_background(
pil_image=im,
desired_width=desired_width,
desired_height=desired_height
)
# output (file like object)
output = BytesIO()
# save image into file-like object
resized_image.save(output, format='JPEG', quality=94)
# get size of file
a_size = output.tell()
# reset to beginning of file-like object
output.seek(0)
self.image.file = InMemoryUploadedFile(
output,
'ImageField',
f"{self.image.name.split('.')[0]}.jpg",
'image/jpeg',
a_size,
None
)
override the save() method of your Model and call the set_image() method before calling the Super().save(*args, **kwargs) method
def save(self, *args, **kwargs):
self.set_image(
desired_width=100, # can be whatever you want
desired_height=200
)
super().save(*args, **kwargs)
- [Django]-Cache for everybody except staff members
- [Django]-Append extra data to request.POST in Django
Source:stackexchange.com