На данный момент мы занимаемся разработкой городской социальной сети. Не «убийцы» Вконтакте и Одноклассников, ее задачи будут в корне иными. В качестве программной основы был выбран Django, написанный на языке Python.
Разрабатывая интерфейс управления личной информацией необходимо было решить задачу: при загрузке пользователем собственной фотографии, ее размер должен быть не более некоторых значений, определенных настройками системы, если фото больше, то необходимо произвести ресайз с сохранением пропорций.
В этой статья я представлю наше решение поставленной задачи. Возможно, оно окажется не оптимальным, поэтому с удовольствием выслушаю ваши комментарии!
Django, ресайз изображений
Функция ресайза изображения. Автоматически изменяет размер, сохраняя пропорции:
def imageResize(data, output_size):
"""
Resize image for thumbnails and preview
data — image for resize
output_size — turple, contains width and height of output image, for example (200, 500)
"""
from PIL import Image
image = Image.open(data)
m_width = float(output_size[0])
m_height = float(output_size[1])
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
w_k = image.size[0]/m_width
h_k = image.size[1]/m_height
if output_size < image.size:
if w_k > h_k:
new_size = (m_width, image.size[1]/w_k)
else:
new_size = (image.size[0]/h_k, m_height)
else:
new_size = image.size
return image.resize(new_size,Image.ANTIALIAS)
Например, при максимально возможных размерах изображения 200×500 px, загружая изображения на 1024×768 px, новые изображения будут — 200×150 px.
Далее перекрываем стандартный джанговский models.ImageField, расширяя метод save_form_data, в котором и будем производить ресайз:
class AvatarImageField(models.ImageField):
def save_form_data(self, instance, data):
from StringIO import StringIO
from django.core.files.uploadedfile import SimpleUploadedFile, UploadedFile
if data and isinstance(data, UploadedFile):
image = imageResize(data, settings.AVATAR_SIZE)
new_image = StringIO()
image.save(new_image, 'JPEG', quality=85)
data = SimpleUploadedFile(data.name, new_image.getvalue(), data.content_type)
# Удаление старого файла
previous = u'%s%s' % (settings.MEDIA_ROOT, instance.avatar)
if os.path.isfile(previous):
os.remove(previous)
# -
super(AvatarImageField, self).save_form_data(instance, data)
Определяем функцию, которая будет возвращать путь к директории сохранения файла, а так же имя файла. Она будет возвращать нужный путь для upload_to файлового поля. В нашем случае имя файла генерируется некоторой хэш-функцией:
def make_upload_path(instance, filename, prefix = False):
# Переопределение имени загружаемого файла.
from utils.hashfunc import get_hash
filename = 'a_' + get_hash('md5') + '.jpg'
return u"%s/%s" % (settings.AVATAR_UPLOAD_DIR, filename)
И, собственно, сама модель данных, поле avatar определяется нашим перекрытым классом AvatarImageField, следовательно, наследует всю его функциональность:
class Avatars(models.Model):
user = models.ForeignKey(User, unique=True)
avatar = AvatarImageField(
upload_to=make_upload_path,
null = False,
blank = False,
)
Готово. Теперь все загружаемые изображение, превышающие определенные в системе размеры будут ресайзиться, сохраняя пропорции.
С удовольствием готов ответить на вопросы, а так же выслушать конструктивную критику этого метода!