Как проверить формат изображения в django ImageField
6 Dmitry [2013-12-24 15:37:00]
В нашем проекте используются Python 2.7, PIL 1.1.7 и Django 1.5.1. Существует ImageField, который работает нормально для многих форматов изображений, включая bmp, gif, ico, pnm, psd, tif и pcx. Однако требование заключается только в разрешении изображений png или jpg. Как это можно сделать?
Upd. Я знаю, что могу проверить расширение файла и HTTP Content-Type. Но ни один из методов не является надежным. Я спрашиваю, есть ли способ проверить загруженное содержимое файла для png/jpg.
python django python-imaging-library
3 ответа
5 Решение Stephen Paulger [2013-12-24 17:07:00]
Вы не указываете, используете ли вы форму Django для загрузки изображения, я предполагаю, что в поле формы выполняется проверка.
Что вы можете сделать, это создать подкласс django.forms.fields.ImageField
, чтобы расширить функциональность to_python.
Проверка типа файла, выполняемая в Django в to_python
, выглядит так:
Image.open(file).verify()
Ваш подкласс может выглядеть примерно так.
class DmitryImageField(ImageField):
def to_python(self, data):
f = super(DmitryImageField, self).to_python(data)
if f is None:
return None
try:
from PIL import Image
except ImportError:
import Image
# We need to get a file object for PIL. We might have a path or we might
# have to read the data into memory.
if hasattr(data, 'temporary_file_path'):
file = data.temporary_file_path()
else:
if hasattr(data, 'read'):
file = BytesIO(data.read())
else:
file = BytesIO(data['content'])
try:
im = Image.open(file)
if im.format not in ('BMP', 'PNG', 'JPEG'):
raise ValidationError("Unsupport image type. Please upload bmp, png or jpeg")
except ImportError:
# Under PyPy, it is possible to import PIL. However, the underlying
# _imaging C module isn't available, so an ImportError will be
# raised. Catch and re-raise.
raise
except Exception: # Python Imaging Library doesn't recognize it as an image
raise ValidationError(self.error_messages['invalid_image'])
if hasattr(f, 'seek') and callable(f.seek):
f.seek(0)
return f
Вы можете заметить, что это большая часть кода из ImageField.to_python
и может предпочесть просто создать подкласс класса FileField вместо ImageField
, а не подклассифицировать ImageField
и дублировать большую часть его функций. В этом случае перед проверкой формата обязательно добавьте im.verify()
.
EDIT: я должен указать, что я не тестировал этот подкласс.
1 smeso [2013-12-24 17:11:00]
Вы можете использовать python-magic, обертку ctype вокруг libmagic, библиотеку, используемую file
в Linux.
Из документа:
>>> import magic
>>> magic.from_file("testdata/test.pdf")
'PDF document, version 1.2'
>>> magic.from_buffer(open("testdata/test.pdf").read(1024))
'PDF document, version 1.2'
>>> magic.from_file("testdata/test.pdf", mime=True)
'application/pdf'
Однако этот метод просто взглянет на mime
информацию. Вы все равно можете загрузить недействительный PNG с правильным mime
или вставить несанкционированные данные в метаданные файла.
1 Chris Hawkes [2013-12-24 15:50:00]
Вы, вероятно, захотите использовать os для этого. Из документов Python.
os.path.splitext(путь) Разделите путь пути в пару (root, ext), так что root + ext == path и ext пуст или начинается с периода и содержит не более одного периода. Ведущие периоды в basename игнорируются; splitext ('.cshrc') возвращает ('.cshrc', ''). Изменено в версии 2.6: более ранние версии могут создавать пустой корень, когда единственным периодом был первый символ.
Пример
import os
fileName, fileExtension = os.path.splitext('yourImage.png')
print fileName
>>> "yourImage"
print fileExtension
>>> ".png"
Итак, если у вас есть ваш ext, отделенный от имени файла, вы должны просто использовать простое сравнение строк, чтобы проверить его в правильном формате.