JasonTS
JasonTS

Reputation: 2589

How to get content of Django ImageField before it is saved?

I'm trying to resize an image while saving an instance of my model.

class Picture(models.Model):
  image_file = models.ImageField(upload_to="pictures")
  thumb_file = models.ImageField(upload_to="pictures", editable=False)
  def save(self, force_insert=False, force_update=False):
    image_object = Image.open(self.image_file.path)
    #[...] nothing yet
    super(Picture, self).save(force_insert, force_update)

The problem is that self.image_file.path does not exist before the model is being saved. It returns a correct path, but the image is not there yet. Since there is no image, I can't open it in PIL for resize.

I want to store the thumbnail in thumb_file (another ImageField), so I need do the processing before saving the model.

Is there a good way to open the file (maybe get the tmp image object in memory) or do I have to save the whole model first, resize and then save again ?

Upvotes: 5

Views: 5039

Answers (3)

Rolando Urquiza
Rolando Urquiza

Reputation: 1450

On your model save method the field value will be a valid FileField or ImageFileField in the case of an ImageField. This django class implements the object file interface (i.e read, write) and it works even before the file is saved with your model, so you can use it as the parameter to PIL.Image.open:

class Picture(models.Model):
    image_file = models.ImageField(upload_to="pictures")
    thumb_file = models.ImageField(upload_to="pictures", editable=False)

    def save(self, force_insert=False, force_update=False):
        img = Image.open(self.image_file)
        # work with img, is an Image object
        super(Picture, self).save(force_insert, force_update)

This works on django >= 1.5.

Upvotes: 0

Denis Kabalkin
Denis Kabalkin

Reputation: 508

I used this snippet:

import Image

def fit(file_path, max_width=None, max_height=None, save_as=None):
    # Open file
    img = Image.open(file_path)

    # Store original image width and height
    w, h = img.size

    # Replace width and height by the maximum values
    w = int(max_width or w)
    h = int(max_height or h)

    # Proportinally resize
    img.thumbnail((w, h), Image.ANTIALIAS)

    # Save in (optional) 'save_as' or in the original path
    img.save(save_as or file_path)

    return True

And in models:

def save(self, *args, **kwargs):
    super(Picture, self).save(*args, **kwargs)
    if self.image:
        fit(self.image_file.path, settings.MAX_WIDTH, settings.MAX_HEIGHT)

Upvotes: 1

Jan Pöschko
Jan Pöschko

Reputation: 5580

Maybe you can open the file directly and pass the resulting file handle to Image.open:

image_object = Image.open(self.image_file.open())

Sorry, I can't test that now.

Upvotes: 0

Related Questions