Автоматический ресайз загружаемых изображений

На данный момент мы занимаемся разработкой городской социальной сети. Не «убийцы» Вконтакте и Одноклассников, ее задачи будут в корне иными. В качестве программной основы был выбран 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,
    )

Готово. Теперь все загружаемые изображение, превышающие определенные в системе размеры будут ресайзиться, сохраняя пропорции.

С удовольствием готов ответить на вопросы, а так же выслушать конструктивную критику этого метода!
Теги:
Python, Django, ресайз, изображения, resize
Добавлено: 17 Сентября 2013 03:20:09 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...