Question

I realize that this is a trivial task and this question was answered multiple times, but I just can't get it. Is there a way to resize and crop image before saving it to disk? All the solutions I found tend to store image, resize it, and then store it again. Can I do this?

# extending form's save() method
def save(self):
    import Image as pil

    # if avatar is uploaded, we need to scale it
    if self.files['avatar']:
        img = pil.open(self.files['avatar'])
        img.thumbnail((150, 150), pil.ANTIALIAS)

        # ???
        # self.files['avatar'] is InMemoryUpladedFile
        # how do I replace self.files['avatar'] with my new scaled image here?
        # ???

    super(UserForm, self).save()
Was it helpful?

Solution

I was able to figure this out. All you need is to save modified file as StringIO and then create a new InMemoryUploadedFile from it. Here is the complete solution:

def save(self):

    import Image as pil
    import StringIO, time, os.path
    from django.core.files.uploadedfile import InMemoryUploadedFile

    # if avatar is uploaded, we need to scale it
    if self.files['avatar']:
        # opening file as PIL instance
        img = pil.open(self.files['avatar'])

        # modifying it
        img.thumbnail((150, 150), pil.ANTIALIAS)

        # saving it to memory
        thumb_io = StringIO.StringIO()
        img.save(thumb_io,  self.files['avatar'].content_type.split('/')[-1].upper())

        # generating name for the new file
        new_file_name = str(self.instance.id) +'_avatar_' +\
                        str(int(time.time())) + \
                        os.path.splitext(self.instance.avatar.name)[1]

        # creating new InMemoryUploadedFile() based on the modified file
        file = InMemoryUploadedFile(thumb_io,
                                    u"avatar", # important to specify field name here
                                    new_file_name,
                                    self.files['avatar'].content_type,
                                    thumb_io.len,
                                    None)

        # and finally, replacing original InMemoryUploadedFile() with modified one
        self.instance.avatar = file

    # now, when form will be saved, it will use the modified file, instead of the original
    super(UserForm, self).save()

OTHER TIPS

I'm not familiar with PIL, but as I can see from docs, you can pass file object as the "file" argument to the "open" function.

Django request.FILES stores UploadedFile objects - simple wrapper around uploaded file (stored in memory or in temporary file), and it supports read, seek, and tell operations, so it could be passed directly to PIL "open" function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top