Created
June 27, 2012 00:48
-
-
Save gregplaysguitar/3000513 to your computer and use it in GitHub Desktop.
Memory-safe ImageField for Django - checks filesize and dimensions before loading the uploaded file into memory.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment