public
Last active

Memory-safe ImageField for Django - checks filesize and dimensions before loading the uploaded file into memory.

  • Download Gist
fields.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
try:
from PIL import Image
except ImportError:
import Image
 
from django import forms
from django.template.defaultfilters import filesizeformat
from django.core.exceptions import ValidationError
 
 
class MemorySafeImageField(forms.ImageField):
"""Image field that checks the size and dimensions of the image in its
metadata *before* trying to load the damn thing into memory.
Pixel dimensions are important because images are loaded into memory
as a bitmap, so MB can easily become GB when working with compressed
image formats.
Requires `max_dimensions` and `max_size` keyword arguments."""
def __init__(self, *args, **kwargs):
self.max_dimensions = kwargs.pop('max_dimensions')
self.max_size = kwargs.pop('max_size')
super(MemorySafeImageField, self).__init__(self, *args, **kwargs)
def to_python(self, data):
# this isn't a mistake - the ImageField.to_python method is what causes the problem
f = super(forms.ImageField, self).to_python(data)
if f is None:
return None
if f.size > self.max_size:
raise ValidationError('Maximum filesize is %s. This file is %s' % (filesizeformat(self.max_size), filesizeformat(data.size)))
 
try:
dimensions = Image.open(f).size
except IOError:
raise forms.ValidationError(u'That doesn\'t appear to be an image')
else:
if dimensions[0] > self.max_dimensions[0] or dimensions[1] > self.max_dimensions[1]:
raise forms.ValidationError(u'Maximum image dimensions are %sx%s px. This file is %sx%s px' % (self.max_dimensions + dimensions))
f.seek(0)
return super(MemorySafeImageField, self).to_python(data)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.