how to compress the image before uploading to s3 in django?
Question:
I am working on an application where a user can upload an image. I want to reduce the size of the image in 200-500kb.
This is my models.py file
class Report_item(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=255, help_text='*Title for the post e.g. item identity')
image = models.ImageField(default="add Item image",
upload_to=get_uplaod_file_name)
def __str__(self):
return self.title + " " + str(self.publish)
And this is my views.py file
class ReportCreate(generic.CreateView):
model = Report_item
fields = ['title','image']
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
form = super(ReportCreate, self).get_form(form_class)
form.fields['title'].widget = TextInput(
attrs={'placeholder': '*Enter UID e.g. CBSE Marksheet Roll nunber 0506***'})
return form
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.owner = self.request.user
self.object.save()
return FormMixin.form_valid(self, form)
I am using Django 1.11 and S3 storage. Kindly help me to compress the image before uploading to s3.
Answers:
So we need to define a save method in models in order to compress the image before save. Following code help me what I want to achieve for my problem.
from io import BytesIO
import sys
from PIL import Image
from django.core.files.uploadedfile import InMemoryUploadedFile
class Report_item(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=255, help_text='*Title for the post e.g. item identity')
image = models.ImageField(default="add Item image",
upload_to=get_uplaod_file_name)
def save(self):
# Opening the uploaded image
im = Image.open(self.image)
output = BytesIO()
# Resize/modify the image
im = im.resize((100, 100))
# after modifications, save it to the output
im.save(output, format='JPEG', quality=90)
output.seek(0)
# change the imagefield value to be the newley modifed image value
self.image = InMemoryUploadedFile(output, 'ImageField', "%s.jpg" % self.image.name.split('.')[0], 'image/jpeg',
sys.getsizeof(output), None)
super(Report_item, self).save()
WIth the help of this 5 Mb image compress to 4 kb approx.
Suppose you want to upload an image after resizing it. You can use below code, just pass the image object and you will get resized image in return.
def GetThumbnail(f):
try:
name = str(f).split('.')[0]
image = Image.open(f)
image.thumbnail((400, 400), Image.ANTIALIAS)
thumbnail = BytesIO()
# Default quality is quality=75
image.save(thumbnail, format='JPEG', quality=50)
thumbnail.seek(0)
newImage = InMemoryUploadedFile(thumbnail,
None,
name + ".jpg",
'image/jpeg',
thumbnail.tell(),
None)
return newImage
except Exception as e:
return e
@jitesh2796, to retain the height to width ratio, modify the accepted answer to include the following:
def save(self):
...
original_width, original_height = im.size
aspect_ratio = round(original_width / original_height)
desired_height = 100 # Edit to add your desired height in pixels
desired_width = desired_height * aspect_ratio
# Resize the image
im = im.resize((desired_width, desired_height))
...
Note you may also need to use round()
to ensure that the aspect ratio is an integer.
This StackOverflow post shows you how to use django-resized to do this easily in your models.py.
I am working on an application where a user can upload an image. I want to reduce the size of the image in 200-500kb.
This is my models.py file
class Report_item(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=255, help_text='*Title for the post e.g. item identity')
image = models.ImageField(default="add Item image",
upload_to=get_uplaod_file_name)
def __str__(self):
return self.title + " " + str(self.publish)
And this is my views.py file
class ReportCreate(generic.CreateView):
model = Report_item
fields = ['title','image']
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
form = super(ReportCreate, self).get_form(form_class)
form.fields['title'].widget = TextInput(
attrs={'placeholder': '*Enter UID e.g. CBSE Marksheet Roll nunber 0506***'})
return form
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.owner = self.request.user
self.object.save()
return FormMixin.form_valid(self, form)
I am using Django 1.11 and S3 storage. Kindly help me to compress the image before uploading to s3.
So we need to define a save method in models in order to compress the image before save. Following code help me what I want to achieve for my problem.
from io import BytesIO
import sys
from PIL import Image
from django.core.files.uploadedfile import InMemoryUploadedFile
class Report_item(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=255, help_text='*Title for the post e.g. item identity')
image = models.ImageField(default="add Item image",
upload_to=get_uplaod_file_name)
def save(self):
# Opening the uploaded image
im = Image.open(self.image)
output = BytesIO()
# Resize/modify the image
im = im.resize((100, 100))
# after modifications, save it to the output
im.save(output, format='JPEG', quality=90)
output.seek(0)
# change the imagefield value to be the newley modifed image value
self.image = InMemoryUploadedFile(output, 'ImageField', "%s.jpg" % self.image.name.split('.')[0], 'image/jpeg',
sys.getsizeof(output), None)
super(Report_item, self).save()
WIth the help of this 5 Mb image compress to 4 kb approx.
Suppose you want to upload an image after resizing it. You can use below code, just pass the image object and you will get resized image in return.
def GetThumbnail(f):
try:
name = str(f).split('.')[0]
image = Image.open(f)
image.thumbnail((400, 400), Image.ANTIALIAS)
thumbnail = BytesIO()
# Default quality is quality=75
image.save(thumbnail, format='JPEG', quality=50)
thumbnail.seek(0)
newImage = InMemoryUploadedFile(thumbnail,
None,
name + ".jpg",
'image/jpeg',
thumbnail.tell(),
None)
return newImage
except Exception as e:
return e
@jitesh2796, to retain the height to width ratio, modify the accepted answer to include the following:
def save(self):
...
original_width, original_height = im.size
aspect_ratio = round(original_width / original_height)
desired_height = 100 # Edit to add your desired height in pixels
desired_width = desired_height * aspect_ratio
# Resize the image
im = im.resize((desired_width, desired_height))
...
Note you may also need to use round()
to ensure that the aspect ratio is an integer.
This StackOverflow post shows you how to use django-resized to do this easily in your models.py.