Created
February 26, 2016 10:24
-
-
Save ambivalentno/9bc42b9a417677d96a21 to your computer and use it in GitHub Desktop.
A form field to handle validation of image + svg.
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
import sys | |
from io import BytesIO | |
from PIL import Image | |
import xml.etree.cElementTree as et | |
from django.core.exceptions import ValidationError | |
from django.forms import ImageField as DjangoImageField | |
from django.utils import six | |
class SVGAndImageFormField(DjangoImageField): | |
def to_python(self, data): | |
""" | |
Checks that the file-upload field data contains a valid image (GIF, JPG, | |
PNG, possibly others -- whatever the Python Imaging Library supports). | |
""" | |
test_file = super(DjangoImageField, self).to_python(data) | |
if test_file is None: | |
return None | |
# We need to get a file object for Pillow. We might have a path or we might | |
# have to read the data into memory. | |
if hasattr(data, 'temporary_file_path'): | |
ifile = data.temporary_file_path() | |
else: | |
if hasattr(data, 'read'): | |
ifile = BytesIO(data.read()) | |
else: | |
ifile = BytesIO(data['content']) | |
try: | |
# load() could spot a truncated JPEG, but it loads the entire | |
# image in memory, which is a DoS vector. See #3848 and #18520. | |
image = Image.open(ifile) | |
# verify() must be called immediately after the constructor. | |
image.verify() | |
# Annotating so subclasses can reuse it for their own validation | |
test_file.image = image | |
test_file.content_type = Image.MIME[image.format] | |
except Exception: | |
# add a workaround to handle svg images | |
if not self.is_svg(ifile): | |
six.reraise(ValidationError, ValidationError( | |
self.error_messages['invalid_image'], | |
code='invalid_image', | |
), sys.exc_info()[2]) | |
if hasattr(test_file, 'seek') and callable(test_file.seek): | |
test_file.seek(0) | |
return test_file | |
def is_svg(self, f): | |
""" | |
Check if provided file is svg | |
""" | |
f.seek(0) | |
tag = None | |
try: | |
for event, el in et.iterparse(f, ('start',)): | |
tag = el.tag | |
break | |
except et.ParseError: | |
pass | |
return tag == '{http://www.w3.org/2000/svg}svg' |
Dont work on django 3
from django.utils import six
https://7webpages.com/blog/how-to-have-svg-allowed-as-an-image-for-django-rest-framework/ references back to this post. I think it's useful.
In latest version of django, you need to update the exception like this (replace line 45-48):
raise ValidationError(
self.error_messages['invalid_image'],
code='invalid_image',
).with_traceback(sys.exc_info()[2])
Also you need to add default validator to this form field to make it work in Django 3. Refer this: https://gist.github.com/ramsrib/4ca2d66fa0063e5acf8b874ecb48cc5f
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In line 44 ifile can be a filepath. Then when it is passed to is_svg it blows up, cause it tries to launch seek method on string object. Need to open this file before seek.