Search code examples
jquerypythondjangockeditordjango-ckeditor

Set image size limit and resize image if is needed


I'm using django-ckeditor for some <textarea> in my forms and use widget=CKEditorUploadingWidget() so I can upload images, that work fine but now I need to set 1mb as size limit for the images.

My first problem is How can I limit the size? if is posible I prefer configure the limit in the django-ckeditor configuration, is this posible? or I have to do it in the server.

My second problem is if the image is bigger of 1mb I need to resize the image in the POST maybe reduce the weight and height at half and if still bigger of 1mb repeat that proccess until the size be less of 1mb, the point is that the user just select the image and the application do all the stuff and the user don´t have to resize the image by him self.

And my last problem is if I need do all this proccess in the client side, what is better, use JQuery or Python with Pillow and proccess the image in the view?

I really lost with this, any help is really apreciated.


Solution

  • There is a LOT of conversation that could go into this. On the other hand there are essentially two separate issues for worrying about image size checking. 1) client side and 2) server side. So let's break that up.

    Server Side

    This is the most important part of the two. Yes, the client side can help reduce the size of the image or inform the user that the image they attempted to upload is too large, but ultimately you want the server to decide what is acceptable.

    So, in Django, theres a few things you can do.

    1) limit file size - In your settings, you can place the following code

    # Add to your settings file
    MAX_UPLOAD_SIZE = "1048576"
    

    Make an image size checker like the following, and run it to to check the size of 'image_field' (name may change). This code returns a validation error if 'image_field' is too large.

    #Add to a form containing a FileField and change the field names accordingly.
    from django.template.defaultfilters import filesizeformat
    from django.utils.translation import ugettext_lazy as _
    from django.conf import settings
    
    def check_image_field_size(self):
        content = self.cleaned_data.get('image_field')
        if content._size > settings.MAX_UPLOAD_SIZE:
            raise forms.ValidationError(_('Please keep filesize under %s. Current filesize %s') % (filesizeformat(settings.MAX_UPLOAD_SIZE), filesizeformat(content._size)))
        return content
    

    source

    this will keep uploaded file sizes from exceeding 1MB, period.

    2) resize the image - Using PIL (Pillow), resize the image.

    import StringIO
    from PIL import Image
    from io import BytesIO
    
    # get the image data from upload
    image_field = self.cleaned_data.get('image_field')
    image_file = StringIO.StringIO(image_field.read())
    image = Image.open(image_file)
    
    # like you said, cut image dimensions in half
    w, h = image.size
    image = image.resize((w/2, h/2), Image.ANTIALIAS)
    
    # check if the image is small enough 
    new_img_file = BytesIO()
    image.save(new_img_file, 'png')
    image_size = new_img_file.tell() 
    
    # if the image isn't small enough, repeat the previous until it is.
    

    3) Lossy compresss the image

     # assuming you already have the PIL Image object (im)
     quality_val = 90
     new_img_file = BytesIO()
     im.save(filename, 'JPEG', quality=quality_val)
     image_size = new_img_file.tell()
     # if image size is too large, keep repeating
    

    Client Side

    Really, the client side only makes things more straightforward for the user. You can try implementing this stuff on the client side, but if you rely on it, there is always the possibility of someone bypassing your client side setup and uploading a 10TB sized 'image' (Some people just want to watch the world burn).

    1) resize or compress - Same as above, but using Javascript or Jquery.

    2) cropping - JCrop is a library that I have used before. It takes some work but it is useful. You can help the user crop the image to a size that is more appropriate and also to give them more power over how the image looks at the new resolution.

    2) helpful messages - If the image a user is uploading is too large, let them know.

    Sources

    How to get image size in python-pillow after resize?

    How do I resize an image using PIL and maintain its aspect ratio?

    How to adjust the quality of a resized image in Python Imaging Library?