21

I am trying to implement a Django ImageField class function for resizing images however I am not certain where this function accepts my new image dimensions

Running on Linux and Python 3.7

I've had a look at this documentation, but can't quite make sense of it: https://docs.djangoproject.com/en/1.11/_modules/django/db/models/fields/files/#ImageField

I'd really appreciate it if someone can show me an example of how to use this function.

EDIT

I haven't successfully managed to resize my image dimensions yet, which is what i am trying to achieve. How may I resize this image before I save it given it is being fetched by ImageField (I found the update_dimensions_fields class function for ImageField however i cant figure out how to use it)

class Posts(models.Model):
    title = models.CharField(max_length=200, blank=True)
    body = models.TextField(blank=True)
    created_at = models.DateTimeField(default=datetime.datetime.now)
    post_image = models.ImageField(upload_to=get_image_path, blank=True, null=True)

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        # I would like to use the function beneath to resize my images before I save them to my database
        self.post_image.update_dimension_fields(self, instance, force=False, *args, **kwargs)

        super().save(*args, **kwargs) # Call the "real" save() method.

    class Meta:
        verbose_name_plural = "Posts"

4 Answers 4

26

You could use the django-resized library. It resizes images when uploaded and stores them for you.

Usage

from django_resized import ResizedImageField

class Posts(models.Model):
    title = models.CharField(max_length=200, blank=True)
    body = models.TextField(blank=True)
    created_at = models.DateTimeField(default=datetime.datetime.now)
    post_image = ResizedImageField(size=[500, 300], upload_to=get_image_path, blank=True, null=True)

    def __str__(self):
        return self.title

Options

  • size - max width and height, for example [640, 480]
  • crop - resize and crop. ['top', 'left'] - top left corner, ['middle', - 'center'] is center cropping, ['bottom', 'right'] - crop right bottom corner.
  • quality - quality of resized image 1..100
  • keep_meta - keep EXIF and other meta data, default True
  • force_format - force the format of the resized image, available formats are the one supported by pillow, default to None
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks stevy, I will make sure to do that. However I haven't successfully managed to resize my image dimensions yet which is what i would like to clarify. How may I resize my image before I save it (I found the update_dimensions_fields class function for ImageField however i cant figure out how to use it)
Dear Stevy, this makes sense - however i am still confused as to where I tell python the target value of img_width and img_height that I want it to be resized to. Sorry for the bother.
Will get back to you soon. Thanks
ModuleNotFoundError: No module named 'django_resized'
Have you installed it using pip install django-resized?
|
5

You can use this method to resize the image before saving it: (you need pip install pillow)

import os
from io import BytesIO
from PIL import Image as PilImage
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile

def resize_uploaded_image(image, max_width, max_height):
    size = (max_width, max_height)

    # Uploaded file is in memory
    if isinstance(image, InMemoryUploadedFile):
        memory_image = BytesIO(image.read())
        pil_image = PilImage.open(memory_image)
        img_format = os.path.splitext(image.name)[1][1:].upper()
        img_format = 'JPEG' if img_format == 'JPG' else img_format

        if pil_image.width > max_width or pil_image.height > max_height:
            pil_image.thumbnail(size)

        new_image = BytesIO()
        pil_image.save(new_image, format=img_format)

        new_image = ContentFile(new_image.getvalue())
        return InMemoryUploadedFile(new_image, None, image.name, image.content_type, None, None)

    # Uploaded file is in disk
    elif isinstance(image, TemporaryUploadedFile):
        path = image.temporary_file_path()
        pil_image = PilImage.open(path)

        if pil_image.width > max_width or pil_image.height > max_height:
            pil_image.thumbnail(size)
            pil_image.save(path)
            image.size = os.stat(path).st_size

    return image

Then use it in the clean method of the image field in your form:

class ImageForm(forms.Form):
    IMAGE_WIDTH = 450
    IMAGE_HEIGHT = 450
    
    image = forms.ImageField()

    def clean_image(self):
        image = self.cleaned_data.get('image')
        image = resize_uploaded_image(image, self.IMAGE_WIDTH, self.IMAGE_HEIGHT)
        return image

To understand how the resize_uploaded_image method works, you may read about how Django handles uploaded files in the docs, here and here.

Comments

3
**

This will work **First of all install "PIL Fork" using 'pip install pillow

from PIL import Image


def __str__(self):
    return self.title


def save(self, *args, **kwargs):
    super(Posts, self).save(*args, **kwargs)
    imag = Image.open(self.post_image.path)
    if imag.width > 400 or imag.height> 300:
        output_size = (400, 300)
        imag.thumbnail(output_size)
        imag.save(self.post_image.path)
class Meta:
    verbose_name_plural = "Posts"

1 Comment

This is not an answer. The question was "before upload". The entire file still would have to be on the server for your stuff to work which means they've already posted their huge image.
1

You can use the django-imagekit library.

Installation

  1. Install Pillow. (If you're using an ImageField in Django, you should have already done this.)
  2. pip install django-imagekit
  3. Add 'imagekit' to your INSTALLED_APPS list in your project's settings.py

Models.py

from django.db import models
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill

class Profile(models.Model):
    avatar = models.ImageField(upload_to='avatars')
    avatar_thumbnail = ImageSpecField(source='avatar',
                                  processors=[ResizeToFill(100, 50)],
                                  format='JPEG',
                                  options={'quality': 60})

Pay attention to the source attribute of ImageSpecField which directs to the actual image field (avatar in this case) as ImageSpecField are virtual in nature, you can read more about it here

Using in your template

<img src="{{ profile.avatar_thumbnail.url }}" />

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.