Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make Thumbnail from Django ImageField.file and convert back to image

So I have a form in Django that is used to upload an image to an ImageField. This works well. I then pass off the request.FILES['image'] off to a function called MakeThumbnail for further processing.

MakeThumbnail is not working too well. I have assembled this from a series of StackOverflow threads, but I think I am missing some crucial concepts. Here is my code.

    def MakeThumbnail(file):
        img = Image.open(file)
        thumbnail = img.thumbnail((128, 128), Image.ANTIALIAS)
        thumbnailString = StringIO.StringIO(thumbnail)
        newFile = ContentFile(thumbnailString)
        return newFile

The stacktrace says I am failing on this line: newFile = ContentFile(thumbnailString). It gives me the following error: expected read buffer, instance found

I think I might be failing back at thumbnail = img.thumbnail((128, 128), Image.ANTIALIAS), though, after looking at the local variables:

thumbnailString : <StringIO.StringIO instance at 0x0000000003B39748>
file : <InMemoryUploadedFile: Desert.jpg (image/jpeg)>
thumbnail : None
img : <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=128x96 at 0x3B25C08>

Notice that thumbnail is none. It should contain something. Does anyone have some hints for me?

thank you!

like image 401
Nick Avatar asked Dec 27 '22 18:12

Nick


2 Answers

Thank you so much for the help, Jan Spurny. I figured it out with your help. So, when img is saved to thumbnailString, a few things need to happen. The code above actually produces an error because we pass an instance to ContentFile instead of a buffer. No matter, we just need to call thumbnailString.read(). But thumbnailString.read() returns ''. Turns out we need to do thumbnailString.seek(0) beforehand. But this did not work either!

Ultimately, I was able to get the image file back to a Django file using InMemoryUploadedFile.

Here is what the code looks like, from beginning to end:

from django.core.files.uploadedfile import InMemoryUploadedFile
import StringIO
def MakeThumbnail(file):
    img = Image.open(file)
    img.thumbnail((128, 128), Image.ANTIALIAS)
    thumbnailString = StringIO.StringIO()
    img.save(thumbnailString, 'JPEG')
    newFile = InMemoryUploadedFile(thumbnailString, None, 'temp.jpg', 'image/jpeg', thumbnailString.len, None)
    return newFile
like image 126
Nick Avatar answered Dec 29 '22 07:12

Nick


From PIL documentation about Image.thumbnail:

Modifies the image to contain a thumbnail version of itself, no larger than the given size. This method calculates an appropriate thumbnail size to preserve the aspect of the image, calls the draft method to configure the file reader (where applicable), and finally resizes the image.

That means your thumbnail is in img, not in thumbnail variable, because Image.thumbnail does not return anything (hence the None)

Another error is putting PIL.Image to StringIO. You'd better save it into StringIO

So your code should look more like this:

def MakeThumbnail(file):
    img = Image.open(file)
    img.thumbnail((128, 128), Image.ANTIALIAS)
    thumbnailString = StringIO.StringIO()
    img.save(thumbnailString, 'PNG')
    newFile = ContentFile(thumbnailString)
    return newFile
like image 42
Jan Spurny Avatar answered Dec 29 '22 08:12

Jan Spurny