Как преобразовать изображение в файл определенного размера?

Я работаю с подушкой, Django и django-imagekit.

Я ищу возможность иметь поле модели изображения профиля (возможно, с использованием класса ProcessedImageField из imagekit), которое будет принимать любое изображение, конвертировать в JPEG, обрезать его до 150x150 и делать его размер файла 5 КБ.

Первые два просты:

profile_picture = imagekit.models.ProcessedImageField(upload_to=get_profile_picture_file_path,
                                                      format='JPEG',
                                                      processors=[ResizeToFill(height=150, width=150)]
                                                      )

Но как я могу обеспечить размер файла 5 КБ? Я мог бы использовать что-то вроде параметра options={'quality': 60} в ProcessedImageField, но это, похоже, только относительно исходного размера файла (насколько мне известно).

Решения не обязательно должны использовать django-imagekit, но это было бы предпочтительнее.


person dcgoss    schedule 15.02.2016    source источник


Ответы (2)


Может, так. Проверьте размер изображения после загрузки и удалите его или уменьшите еще раз с помощью переопределенного save метода:

class Images(models.Model):
    profile_picture = imagekit.models.ProcessedImageField(upload_to=get_profile_picture_file_path,
                                                  format='JPEG',
                                                  processors=[ResizeToFill(height=150, width=150)]
                                                  )

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):

        if os.stat(get_profile_picture_file_path + "/" + self.profile_picture.new_name).st_size > max_size:
            do_something_further_image_processing_to_decrease_size

        super(Images, self).save()
person PaulWebbster    schedule 15.02.2016
comment
Это хорошее начало для проверки того, что файл слишком велик, но логика в do_something_further_image_processing_to_decrease_size действительно является важной частью вопроса. Как вы можете гарантировать, что каждый раз уменьшаете размер файла до определенного размера (даже с изображениями разного разрешения / качества JPEG)? - person dcgoss; 16.02.2016
comment
Я, вероятно, добавлю сюда итеративную функцию, которая каждую итерацию уменьшает разрешение на 10% или другой коэффициент, соответствующий текущему размеру создаваемого изображения. PIL дает вам такую ​​возможность. - person PaulWebbster; 17.02.2016

Раньше у меня была аналогичная проблема, поэтому я решил оптимизировать изображения с помощью инструментов ОС (jpegoptim, optipng и т. Д.), Вызываемых из django после сохранения модели с использованием сигналов (вы также можете использовать метод сохранения overriden). Эти инструменты оптимизируют и удаляют метаданные из ваших изображений. С другой стороны, вы можете изучить средний коэффициент сжатия и размер файлов jpg размером 150x150 и попытаться угадать лучшее качество для настройки, проверьте следующее: (степень сжатия jpeg)

Это мой код для оптимизации файлов после их сохранения, я использую простую библиотеку эскизов, которая предоставляет мне сигналы после сохранения:

@receiver(saved_file)
def optimize_file(sender, fieldfile, **kwargs):
    optimize(fieldfile.path)


# thumbnail optimization
@receiver(thumbnail_created)
def optimize_thumbnail(sender, **kwargs):
    optimize(sender.path)

def optimize(path):
    """
    install image utilities
    apt-get install jpegoptim optipng pngcrush advancecomp
    :param path:
    :return:
    """
    # taken from trimage (http://trimage.org/)
    runString = {
        ".jpeg": u"jpegoptim -f --strip-all '%(file)s' ; chmod 644 '%(file)s'",
        ".jpg": u"jpegoptim -f --strip-all '%(file)s' ; chmod 644 '%(file)s'",
        ".png": u"optipng -force -o7 '%(file)s' && advpng -z4 '%(file)s' && pngcrush -rem gAMA -rem alla -rem cHRM -rem iCCP -rem sRGB -rem time '%(file)s' '%(file)s.bak' && mv '%(file)s.bak' '%(file)s' ; chmod 644 '%(file)s'"
    }

    ext = splitext(path)[1].lower()
    if ext in runString:
        subprocess.Popen(runString[ext] % {'file': path}, shell=True)
person César    schedule 19.07.2016