1

I have a an HTML form that allows images upload. I want to save the original image to S3 storage and then convert it to thumbnail and save the thumbnail to the same storage.

I could only save the original image but after converting it to thumbnail using PIL when I try to save it I get "Server error 500"

My views code is as follow,

from django.core.files.storage import default_storage as storage
class upload(View):
def post(self, request):
    image = request.FILES['pic']
    storage.save(image.name, image)
    thisfile = storage.open(image.name)
    newimg = Image.open(thisfile)
    thumb = newimg.resize((128,128), Image.ANTIALIAS)
    storage.save("newimagename", newimg)

    #Trying to save it this way doesn't work either
    #thisobj = userProfile.objects.get(user= request.user)
    #thisobj.image = newimg
    #thisobj.save()

I tried some print statements to make sure that it was converting the file with no problem and it was but it saved it to memory and it prints like,

<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=600x600 at 0x105C1DEF0>

I tried overwriting the save method in models.py but I get the same error

def save(self, *args, **kwargs):
    super(userProfile, self).save(*args, **kwargs)
    if self.image:
        self.image.name = "y.JPG"
        image = Image.open(self.image.path)
        image = image.resize((128,128), Image.ANTIALIAS)
        image.save(self.image.path)
Hossam Mohamed
  • 126
  • 1
  • 7

3 Answers3

1

Try this:

 def save(self, *args, **kwargs):
     super().save(*args, **kwargs)
     img = Image.open(self.image.path)
     if img.height > 128 or img.width > 128:
         output_size = (128, 128)
         img.thumbnail(output_size)
         img.save(self.image.path)
Mahrez BenHamad
  • 1,791
  • 1
  • 15
  • 21
1

After lots of digging I came up with 2 different solutions!

1- Overriding the "Save" method in models.py as follows,

from PIL import Image
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
    def save(self, *args, **kwargs):
    super(userProfile, self).save(*args, **kwargs)
    previous = userProfile.objects.get(id = self.id)
    if self.image.width > 128:
        orig = Image.open(self.image)
        orig.thumbnail((128,128), Image.ANTIALIAS)
        fileBytes = BytesIO()
        orig.save(fileBytes, format="JPEG")
        memoryFile = InMemoryUploadedFile(fileBytes, None, str(self.user) + "_thumb.JPG", 'image/jpeg',1, None)
        self.image = memoryFile
        self.image.save(self.image.name, self.image)

2- Save an uploaded file using the default storage.

from io import BytesIO
from django.core.files.storage import default_storage
from django.core.files.uploadedfile import InMemoryUploadedFile
class upload(View):
  def post(self, request):
    image = request.FILES['pic']
    #Save the image first to the DB
    default_storage.save(image.name, image)
    #Open the file in the DB
    thisdude = default_storage.open(image.name)
    #Use the opened file in the DB in Images
    img = Image.open(thisdude)
    # Resize that babe
    img.thumbnail((128, 128), Image.ANTIALIAS)
    #Get the Bytes of the file from memory
    thumbnailString = BytesIO()
    #Save the image with the bytes as JPEG
    img.save(thumbnailString, format='JPEG')
    #Get the file in the memory
    thumb_file = InMemoryUploadedFile(thumbnailString, None, 'foo.jpg', 'image/jpeg',1, None)
    #Save it to the DB
    default_storage.save("abc.jpg", thumb_file)
    return redirect("index")
Hossam Mohamed
  • 126
  • 1
  • 7
0

There is a good library you could have used that does exactly what you wanted to do.

https://github.com/codingjoe/django-stdimage

It makes thumbnails of the original file on upload. Also it is fully compatible with S3.

garchompstomp
  • 120
  • 10