Gorky
@Gorky
Веб-разработчик

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

Всем добрый день друзья. Я сейчас делаю бэкенд для мобильного приложения заказчика. Хочу отделить хранение оригинала и уменьшенных копий изображений от сервера с кодом. Так же хотелось бы для удобства фронтендеров сделать запрос изображений нужного размера "на лету".

То есть желаемый пример реализации условно такой:
1. Фронтенд присылает на бэкенд фотографию, выбранную пользователем.
2. Я не сохраняю ее там же у себя, а загружаю в какой-то сервис (облачное хранилище? cdn?) через апи, получаю в ответ уникальный идентификатор этого изображения. Т.е. по сути в бэкенде храню только этот id и ничего больше.
3. Идентификатор используется на фронтэнде, позволяя получить это изображение разного размера для вывода в интерфейсе, запрашивая их на лету через адрес. Схематично, такой: https://some-cloud-storage.ru/image-id/?width=500. Т.е. адрес можно просто вставить в тег img src="..." и получить уменьшенное изображение.

Собственно, вопрос - как это реализовать, через какой сервис?
Важное уточнение - для заказчика принципиально важно не использовать зарубежные проекты, вроде амазона.

Я примерно понимаю что мне надо видимо смотреть в сторону cloud storage и cdn в яндекс облаке или вк облаке. Как туда загружать оригиналы изображений понимаю. А вот как сделать так чтобы можно было запрашивать потом копии любого размера - искал искал и не нашел что-то. Неужели самому предварительно пережимать и загружать? И вроде как хранилище и cdn надо тоже объединить вместе (cdn поверх хранилища?).

Вроде задача звучит не очень сложно, но в единую картинку не собирается. Хочется какое-то относительно простое и понятное решение.

В общем если кто-то реализовывал подобное, буду рад любым ссылкам на статьи, рекомендациям и объяснениям.
  • Вопрос задан
  • 2867 просмотров
Пригласить эксперта
Ответы на вопрос 6
alexey-m-ukolov
@alexey-m-ukolov Куратор тега Веб-разработка
Можно поднять бесплатную версию imgproxy. Единственный затык - у них из облаков Amazon, Google и Microsoft. Но можно вполне накостылить что-то рядом, что будет хранить файлы локально и будет уметь работать с вашей основной системой.
Ответ написан
Комментировать
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
Это болючая задача которую мне приходится решать на каждом проекте.
"Готовое" решение для симфони - liip imagine bundle, но пока все конфиги изучишь - неделя пройдет.

Я обычно подключаю вручную:
1. свой класс отвечающий за масштабирование + обрезку + смену формата на webp
2. 2 маршрута API - один называю blueprint, второй image. Блюпринт выдает JSON-ом все возможные ссылки с предустановленными параметрами, а image - отдает картинку
3. и оборачиваю это в phpleague flysystem, чтобы при случае переключиться на амазоновское, дропбоксовое или свое собственное хранилище, а изначально использовать родную файловую систему
4. для обрезки подключаю gumlet, он может не идеален, но немного проще чем использовать встроенный gd или устанавливаемый imagick, где придется учить настройки, гумлет все-таки немного преднастроен по качеству и сжатию (под капотом все равно gd или imagick используется, просто обертка)

Вот пример на тестовом сайте:
/api/v1/uploads/image/2024/02/000029_1605538227_415880_big1.jpg?presets=group.all
/uploads/image/size-original/2024/02/000029_1605538227_415880_big1.jpg
/uploads/image/size-jpg2webp/2024/02/000029_1605538227_415880_big1.webp
/uploads/image/size-jpg2webp-100-100/2024/02/000029_1605538227_415880_big1.webp

65f2b0d786d48373675526.jpeg

Но там много моментов, которые так просто не описать.
1. Во первых сначала масштабирование. Тут придется думать по длинной стороне, короткой стороне, или по aspect ratio.
2. Потом обрезка, если идеально привести не удалось. Отдельно придется подумать где точка центра - вверху-центре или в центре-центре.
3. Потом после обрезки скорее всего ты получишь raw content изображения, чтобы его сохранить в файл нужно его поймать ob_start()/ob_get_clean(), и обеспечить чтобы входящая ссылка всегда приводила к созданию картинки с тем же путем, и если она уже есть - не тратила время а отдавала готовую. Опять же - если сделать "произвольный размер" - то твой сервер очень легко нагнуть, сделав мини-ддос, чтобы он сгенерировал все возможные сочетания размеров от 0 до 2000 по X/Y, получится 4 миллиона картинок. Поэтому так или иначе надо предусматривать ключ или пароль, позволяющий это делать, чтобы снаружи не долбили ерундой.
4. Потом форматы. Родное изображение было в .jpg, а итоговый хочется webp. Получается что итоговое изображение будет либо с двумя расширениями (и пхпшная функция pathinfo еще заставит попотеть), либо оригинальное разрешение будет получено из jpg2webp, а итоговое можно указать любое, но работать должно только если оно webp.

В общем, гемор что надо тебя ждет. Но реализуемо.
Ответ написан
ThunderCat
@ThunderCat Куратор тега Веб-разработка
{PHP, MySql, HTML, JS, CSS} developer
Вариантов масса, все зависит от кучи неозвученных нюансов, давайте опишу первые 3 приходящие в голову:
1) Хранить готовые изображения разного размера, ключ для которых в таблице будет один, а по факту, в зависимости от гет параметров тащится нужного размера, сопоставленное по ключу и размеру.
То есть табличка имеет вид : [id] | key | size | real_aws_key , через софт бэкенда тянете картинку с сервера хранения, отдаете в виде потока.
2) NGINX + модуль, тут вроде нужно будет подергать настройки, и поплясать с бубном, но зато решение практически коробочное. Минус - жрет проц. Можно организовать то же самое, но через софт, тот же imagick например.
3) Хранить превьюшки локально, на облако заливать только большие файлы, по запросу тащить нужные превьюхи из папок, например что-то типа \storage\images\500\[image_id].jpg
Ответ написан
Если нужны готовые решения, то:
https://github.com/Pixboost/transformimgs
https://github.com/thumbor/thumbor
Cloudinary
Ответ написан
Комментировать
Noizefan
@Noizefan
Uploadcare.com делает именно все то, что ты описал
Ответ написан
Комментировать
Можно поднять сервис с этой либой, она умеет делать обрезку, webp/avif, и любые манипуляции вроде блюра, на лету, по гет параметрам от фронтов
https://glide.thephpleague.com/

путь до исходных картинок указывается чрез League\Flysystem\Filesystem, она умеет работать с облачными хранилищами
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы