Как изменить размер источника с помощью sorl-thumbnail?
Я искал в Интернете свой вопрос и не смог найти четкого ответа ни на один пример.
По сути, я хочу использовать sorl и хочу изменить размер исходного изображения во время сохранения модели, чтобы уменьшить его размер до 640x480, чтобы я не заканчивал тем, что сохранил оригинальные 2,5 МБ файлы пользователя на диске. Затем я буду использовать шаблоны тегов для создания обычных миниатюр из моего источника, как описано в sorl.
Я натолкнулся на несколько источников, ссылающихся на использование поля модели ThumbnailField, которое должно быть доступно в sorl.thumbnail.fields. Смотрите ссылку здесь. Тем не менее, в моей современной копии sorl из ствола я не вижу ни ThumbnailField, ни ImageWithThumbnailsField. Моя попытка импортировать его в модель проваливается соответственно. Я вижу, что эти ссылки старые, и мне интересно, смогу ли я достичь того же с помощью современной технологии sorl.
С другой стороны, в документации sorl указан только ImageField из sorl.thumbnail (см. Здесь), который не имеет аргумента размера для управления изменением размера источника.
Кстати, я вижу, что эта функциональность доступна с easy_thumbnail, который принимает входной параметр source_resize.
Любая помощь будет оценена!
РЕЗЮМЕ
Я принял приведенный ниже ответ, однако я чувствую, что естественная поддержка sorl для этого варианта использования может быть очень полезна - т.е. добавление параметра resize_source в ImageField sorl для разрешения изменения размера исходного изображения. Ниже приведены два фактора, по которым это может быть полезно в данной области:
Не хранить огромные оригинальные изображения пользователя, если оно не требуется для вашего приложения. Экономия дискового пространства.
Не тратьте лишний процессор на изменение размера миниатюр из этих огромных исходных изображений, если у вас нет особых причин высокого качества. Чтобы избежать этого, можно написать вложенные теги в шаблонах в виде миниатюр из изображений меньшего размера, но это может стать раздражающим очень скоро.
3 ответа
Sorl-х ImageField
что вы упоминаете, это просто нормальный Django ImageField
с дополнительным преимуществом управления удалением кэшированных миниатюр. Изменение размера при первоначальной загрузке не выполняется - это то, что вы должны реализовать самостоятельно, используя представление, которое вы используете для загрузки. Документы показывают, как это сделать. Вы можете использовать sorl в этом представлении, чтобы выполнить саму фактическую операцию изменения размера, используя API-интерфейсы низкого уровня.
РЕДАКТИРОВАТЬ
Более быстрая альтернатива - просто изменить размер изображения, когда модель сохраняется с помощью sorl. Вы можете сделать что-то вроде следующего (хотя полностью не проверено!)
from sorl.thumbnail import get_thumbnail
class Foo(models.Model):
image = models.ImageField(upload_to...)
def save(self, *args, **kwargs):
if not self.id:
# Have to save the image (and imagefield) first
super(Foo, self).save(*args, **kwargs)
# obj is being created for the first time - resize
resized = get_thumbnail(self.image, "100x100" ...)
# Manually reassign the resized image to the image field
self.image.save(resized.name, resized.read(), True)
super(Foo, self).save(*args, **kwargs)
это будет означать, что у вас будет 2 версии одного и того же образа на диске - одна, в которой поле изображения django решит сохранить его (upload_to
путь), а тот, где уменьшенное изображение сохранено, - уменьшенное изображение. Это, наряду с тем фактом, что изображение загружается и сохраняется дважды, являются недостатками этого подхода. Это быстрее реализовать, хотя
Я обнаружил недостаток в приведенном выше коде: "У str нет метода chunck()", если кто-то захочет его использовать. Вот мое исправление:
from sorl.thumbnail import get_thumbnail
from django.core.files.base import ContentFile
class Foo(models.Model):
image = models.ImageField(upload_to...)
def save(self, *args, **kwargs):
if not self.id:
super(Foo, self).save(*args, **kwargs)
resized = get_thumbnail(self.image, "100x100" ...)
self.image.save(resized.name, ContentFile(resized.read()), True)
super(Foo, self).save(*args, **kwargs)
Некоторое время я искал решение и в конце концов написал приложение django-resized.
В следующем коде используется PIL Engine (часть sorl-thumbnail) для обрезки изображения с именем picture.jpg
(проверено с использованием Python 3.8
а также sorl-thumbnail==12.6.3
):
#
# Change this import to get the Engine of your underlying libraries.
# Options are: convert_engine, pgmagick_engine, pil_engine, vipsthumbnail_engine or wand_engine.
#
from sorl.thumbnail.engines.pil_engine import Engine
# This object has all we need
engine = Engine()
#
# When receiving data from a request
# you probably have a BytesIO instance ready to use like:
#
# im = engine.get_image(my_bytes_io)
#
with open("picture.jpg", "rb") as f:
im = engine.get_image(f)
im_crop = engine.crop(im, (535, 535), options={'crop': 'smart'})
im_crop.save("picture-thumb.jpg")
Вместо изменения save
метода, у меня была бы вспомогательная функция для уменьшения размера изображения (с помощью строк выше) и вызывала ее из представления или формы Django перед обновлением поля изображения. Хотя это сработает наsave
сам.
С другой стороны, Engine API имеет больше полезных функций, которые могут быть полезны! Этот API существует с момента первого коммита, поэтому, на мой взгляд, вряд ли он изменится в будущем:create
, cropbox
, orientation
, flip_dimensions
, colorspace
, remove_border
, calculate_scaling_factor
, scale
, crop
, rounded
, blur
, padding
, write
, cleanup
, get_image_ratio
, get_image_info
, get_image
, get_image_size
, is_valid_image
.