Pull to refresh

Comments 48

Не совсем понятна поставновка задачи, но если необходимо дать клиенту, или контент менеджеру вставить в текст страницы уменьшенную копию изображения, то я решал эту проблему так. В редакторе (FCKeditor) в скрипты которые инсертят картинку в текст добавил ещё один селект «вставить маленькое изображение» — да/нет. Человек грузит картинку, ставить опцию в вариант «да», скрипт парсит адрес картинки и дописывает в начале пути /thumb/path/to/pic.png. Дальше адрес ловится через htaccess и рулится в нужный контроллер (CodeIgniter), где проверяется есть ли кэш этой картинки на диске, если нет, то ресайзит и выдаёт, сохряент в кэш, а если находит — сразу выдаёт кешированную картинку. Плюс к тому при вставке изображения в текст, картинка оборачивается в ссылку и ей проставляется класс .ph, который является триггером для prettyPhoto. Т.е. это Ваш 4ый вариант, но с кешированием и без указания размеров картинки. А вот эти картинки ресайзятся по большей стороне до 200 пх, с сохранением пропорций. Вот и все.
Оставлю это здесь, чтобы все новопришедшие видели.
Автор упомянул, что он рассматривал вариант использования nginx.
Так вот, у nginx есть замечательный модуль HttpImageFilterModule. Он умеет делать ресайзить, поворачивать и кропать изображения. Минус один — он не кеширует, но тут на помощь приходит кто? Тот же самый nginx, который кеширует вывод изображений. Результат — у нас кешируются отресайзенные изображения, ресайз делается самим nginx, который это делает напорядок быстрее всяких решений в языках. Вариант того, что кто-то может вам убить сервер механически обходя сайт и генерируя разные изображения — в конфиге жестко прописываете пути по которым ресайзить.

p.s. В комментах ниже никто не упомянул подобного решения)
очень интересно. Обязательно присмотрюсь к этому модулю.
Хотите кусок конфига, который все делает?))
Почитал. Да. Решение с nginx круче и серьезнее. Мне нравится. Пожалуй время затраченное на пост и на демон, стоит того, что бы увидеть ваш комментарий. Не знал о этом модуле. Теперь знаю)
Есть еще и django-приложение испольщующее ngx_http_image_filter_module — django-nginx-image
И статья автора описывающая это приложение на русском языке.
Я давно уже пользуюсь данным приложением и производительность выше чем у всяких sorl-thumbnail/easy_thumbnails итд.
Единственный минус — зависимость от nginx(что меня совсем не смущает и не является минусом в моем случае)
Из своей практики могу сказать так — очень редко где надо ресайзить изображения с точностью до пикселя.

Обычно на сайтах используются 2-3 размера: маленькое превью => оригинальный файл либо же маленькое превью, превью побольше, вид в для показа «на весь экран».

Для этого хватает обработчика где передается id размера.
Например /image/dynamic/preview/1.jpg или же /image/dynamic/full/1.jpg

А сам обработчик пишется так (примерный код) .htaccess:

RewriteCond %{REQUEST_URI} ^/image/dynamic/(.+)$
RewriteCond %{DOCUMENT_ROOT}/папкакэша/%1 -f
RewriteRule. /папкакэша/%1 [L]
script.php [L]

В таком случае если apache найдет файл в кэше — отдаст его, если нет — запустит скрипт index.php, который сгенеритт файл в папкукэша + сразу отдаст его.
Замедление только на этапе создания кэша, кроме того это можно автоматизировать при обнулении ( нагегенрить скриптом из базы все варианты если надо ). После юзанья в продакте в течении некоторого времени «нагнуть» сайт атакой по ресайзингу крайне проблематично )

Если жу нужна субпиксельная точность — то мне кажется вернее рубить размеры на окна, а внутри окна масштабировать средствами браудера — ибо лишней инфы при окне скажем в 10-20 пикселей будет не так много как все эти файлы на сервере.

Ну это все мое видение конечно, плюс в Вашем варианте есть возможность синхронизации.
у вас хороший вариант, я лишь добавил проблему синхронизации удаленных изображений.
по сути, ваш способ мало чем отличается от остальных и проблемы не решает. я бы даже сказал, создает проблем больше, чем способ 3,4,5.

1. отметаем. это даже не вариант решения, это — сама проблема
2. если картинки должны идеально ресайзится — это единственный и лучший вариант. если допускается погрешность — отметаем.
3. имхо, самый лучший вариант. не совсем понял что значит «Не всегда размеры, бывают подходящими под задачу», но если Вы имеете ввиду, что не всегда картинку можно так ресайзнуть, чтобы она нормально выглядела — да, это так, но и Ваш вариант решения (6) эту проблему не решит. Я бы сказал, что это 2 совершенно разные проблемы.
4. нормальный вариант. нагрузка? ну разве что у Вас будет туча картинок, а сайт подвергнется хабраэффекту при первом-же запуске. в остальном все должно отработать нормально. А насчет «в случае если злоумышленник решит создать скрипт в котором будет циклически подставлять различные пути, заставляя сервер ресазить» — можно просто ограничить количество вариантов. 100x150 и 200x300, все остальное — нафиг.
5. то же самое, что и 4, но на скриптовом языке. по поводу недостатков: «Недостатком такого подхода является излишний код» — он будет в любом варианте, кроме самых торопных (1 и 2). «в случае удаления оригинального изображения, отрезайзенные изображения останутся храниться на жестком диске» — можно (и нужно) сделать обработчик в админке (при удалении оригинала).
6. теперь к Вашему способу. Почему я сказал, что он создает даже больше проблем:
1. если это крон, то обновление будет происходить максимум раз в минуту. т.е. 1 минуту после заливки изображения на сайте будет косяк
2. если это менеджер (nohup *** &), то есть вероятность, что Вы забудете написать скрипт, который перезапустит менеджер после, например, ребута.
3. не вчитывался в код, но сразу видно, что он довольно-таки объемный. хотя в других случаях легко решается одной строчкой convert.
3. не совсем понял что значит «Не всегда размеры, бывают подходящими под задачу»,
допустим вы выделили размеры xs — 100x100 s -200x200 l — 800x600 xl — 1200x1600 (например). а нам нужно вывести картинку размером 300х300, конечно мы не сильно пострадаем, если выведем L (800x600) и сократим, но тем не менее, это не хорошо.

4. Добавить логику на проверку размерности (т.е что нафиг, а что нет) — это хорошо, но как решать проблему смены изображений у публикации. Когда удаляется оригинальная картика, то как найти отресазенные?

про недостатки
1. это не крон
2. Так рассуждать — вообще демонов не писать. Есть же системы мониторинга.
3. увы)
3. ну вот об этом и говорю, что да, ее придется обрезать. однако вариант с кроном такую проблему все-равно не решит иначе. она не относится к задаче, это совсем другая проблема. Вы вроде как говорите о том, как организовать автоматический ресайз, а не о том, как именно он будет ресайзить.

4. предположительно, я бы сделал так, чтобы существовал оригинал и несколько отресайзанных копий, структурированных таким образом, чтобы эти копии можно было найти и удалить при удалении оригинала.

Так рассуждать — вообще демонов не писать. Есть же системы мониторинга.
Вы серьезно? :) ну совсем не та задача, для которой еще и систему мониторинга прикручивать. Я просто имею ввиду, что создание такого демона создает дополнительный момент, о котором нельзя забывать (блин, забыл запустить демона!). а зачем, если можно сделать проще?

на самом деле, почитав соседние комменты, пришел к мнению, что 4-ый вариант и правда наиболее подходящий и гибкий.
да нет… крутить систему мониторинга ради одного демона — соглашусь как-то странно, но если она уже есть и демон трудится не один? то почему бы и нет?)

> таким образом, чтобы эти копии можно было найти и удалить при удалении оригинала.
так в этом то и проблема? каким образом нужно хранить ресайзы, что бы их легко можно было найти и удалить?
Ну к примеру есть папка images в ней есть папка original и несколько папок с именем совпадающем с размерами ресайзов (300х300 и т.д.).
В папке original лежат оригиналы изображений. В остальных отресайзеные изображения с именем оригинала.
В чем проблема удалить все ресайзы, зная их имена, и получив названия всех папок, кроме original?
т.е пройтись по всем и удалить. ну тоже хорошо :-)
Считаю 4ый вариант самым оптимальным.

При первом обращении если файла нет, ресайзим и создаем нужные папки\файлы, можно в приложении указать какие разрешены размеры (и никакой злоумышленник не забьет дисковое пространство и не положит сервер, т.к. статика будет отдаваться веб-сервером без участия интерпретатора, его участие будет только тогда когда запрашивается изображение)

Плюс метода в том что если необходимо поменять размеры изображений на сайте( скажем их там 100500 штук), то достаточно поправить только ссылочку, скажем вместо /img/100x50/img.jpg написать /img/120x60/img.jpg, и все будет прекрасно работать.

С удалением кэша для 100х50 думаю проблем не возникнет.

Есть другой подход, где кэш хранится хрен пойми где, и при обращении по ссылке к изображению, подгружается хрен пойми сколько моделей, контроллеров и представлений, проверяют существует ли закэшированное изображение если существует — показывает его, если нет — создает и показывает. Вопрос людям, которые так делают: «НАХРЕНА?!»
Мне часто приходится разрабатывать сайты где размеры бывают такие 149х85 и еще гора других «красивых» размеров. И поэтому подход 4 считаю оптимальный для решения такой задачи.
Да и к ссылке обычно добавляют не только размеры но и информацию кропать или нет, если кропать то с какой части изображения(верх, середина, низ, право, лево), процент сжатия. Что очень гибко!
Вы наверное недопоняли проблему удаление неиспользуемых изображений. Если меняется изображение у публикации, то старое (там где оно загружено) удаляется, а новое создается. Как удалить созданные ресайзы для этого изображения?
Возможно и недопонял.

Если меняется изображение:

1. Удаляем оригинал старого изображения ( ресайзы остаются )
2. Раз в 1-2 месяца, чистим весь кэш ресайзов. ( ведь к старым или редко обращаются или вообще не обращаются )
3. «Разогреваем» кэш ресайзов чем нибудь, или постепенно сами пользователи «разогреют»

Вывод: Держим кэш в актуальном состоянии. Кэш не разрастается. Ну и минус в том, что раз в 1-2 месяца, немного повышенная нагрузка на сервер.
Неплохо. Только будет один минус — если есть страница, где выводится много различных превьюшек, то сайт призадумается при генерации этих изображений (если это после очистки кэша ресайзов). Хоть такой вариант маловероятен, но тем не менее…

Т.е ваш вариант неплох. А чем плох мой? Т.е какие именно недостатки у него?
В вашем варианте я не понял что делать, если на сайте залито 100500 изображений, много изображений на одной странице, на сайте постоянно сидит много народу, и нам нужно поменять размер изображений отресайзенных. (скажем резали по ширине и высоте, нужно порезать только по ширине, а высота пропорционально)

Ждать пока скрипт отресайзит? А пользователям посылать на несуществующие изображения?

Вот этот момент мне не понятен.
алгоритм то тут немного не быстрый. Сначала создается папка с новым размером. Демон ее хватает и работает.
А пока изменить во вью ссылку на новые изображения, пока закомитеть это, проверить, выложить — пройдет достаточно времени, что бы создались нужные изображения.
Ну и схавает даже те изображения, к которым очень редко обращаются, и возможно обратятся только через год…
Ваш способ тоже не идеален. Если фотографий к примеру 10 млн и поступила задача создать новый размер, сколько времени вы на это потратите? А если их в 10 раз больше?)
демон работает в фоне. Пока создаются новые размеры — можно публикацию написать
Хотя вы правы — в этом случае (хоть он и маловероятен 100 млн изображений) — я бы создал инструменты по созданию новых размеров и скрипт конвертации выполнился бы пакетно.
Тут важный момент: важно не только сделать быстро! но и при этом не хранить миллион кропов… которые не всегда нужны…
Самая спорная часть вопроса — именно ресайз. Нужен ли он? Я на своем fullhd-экране не могу смотреть на сайты, приходитя выставить 150% приближение, чтобы хоть что-то было видно. И знаете что? Картинка 100*100 натянутая на площадь в 9/4 раз больше выглядит паршиво. Да и вообще, интернеты быстрые нынче. Мобильная версия — да, но там своя специфика.
А какие нынче браузеры ресайзят картинки при резайзе страницы? Мне действительно любопытно: какие и зачем они это делают?
хром. Ресайзит страницу очень гармонично (все картинки, в том числе фоны), только иногда при миксе фонов есть проблемы (например, при входе на хабр можно заметить).
Т.е. по сути выходит что-то вроде проблемы новых айпадов с сетчаточными дисплеями.

Я, конечно, не говорю об огромных фотографиях. Сам когда-то сделал проще некуда — обращаемся по ссылке /img/asd_small.jpg — ресайзит и выдает картинку. Результат кеширует, повторно через апач.
Да серьезно, если картинка больше в два-три раза, зачем ее уменьшать? Я понимаю, в интернете сейчас популярен тренд адаптивного дизайна, но много ли сайтов его поддерживают? Чтобы визуально страница была нормального размера и вида нужен зум (что устройства с retina-дисплеем автоматом делают), при этом изображения становятся размытыми (что логично).

Я не утверждал, что огромные изображения нужно оставить в старом размере.
есть лента публикаций. У каждой публикации есть заглавная картинка. Создаем страницу анонс новостей за прошлый месяц и получаем 100 сообщений с маленькими картинками.
По вашему, зачем их ресайзить??? Вы предлагаете их выдать по первому варианту? вместо 1 мб страницы выдастся 100 мб? Действительно спорный вопрос.
погодите, 1 мегабайт на картинку? Серьезно? Вы вообще прочитали то, что я написал? Я имел ввиду случай, когда картинку 30кб сжимают до 15кб. Легко подсчитать, что это 3МБ, ничтожно мало. Не нужно так преувеличивать.
А я имел в виду, что я пишу публикацию (новость, статью), и выбираю изображения для нее с компа. А они не 30 кб.
Вы грузите картинку, ее надо сжать, так? Зачем демон? Сжимаем при сохранении. Ну и что, что она чуть больше, чем нужно (не 100 на 100, а 300 на 300), потом не нужно будет ее пережимать. Вот об этом я и написал, ни к чему городить систему с демоном, если мы пережимаем картинку только один раз.
во внерабочее время сижу с юсб-модема пчелайн, скорость отвратительная, в среднем 20-40Кбит/с.
Для меня разница 3МБ и 1,5МБ это значительно!
Таких людей очень много, и не надо включать «эгоиста», нужно чтобы все было оптимизировано, работало максимально быстро и кушало максимально мало ресурсов.
А вы уверены, что это того стоит? «кушало максимально мало ресурсов» — а вы не учитываете то, что серверу нужно тоже трудиться? Нужно вам большее разрешение — приходится ВСЕ заново пережимать.

Думаю, спор несостоятельный. Я когда-то на диалапе сидел, тоже ругал весь мир, теперь мне важнее, чтобы текст на картинках не мылился. Кто-то из нас точно прав, и не обязательно кто-то один. :)
Ну сервер один раз напрягся чтобы пережать, а потом отдает легкие файлы на протяжении долгого, счастливого времени. И не тратит ресурсы понапрасну. А Вы предлагаете гонять ему туеву хучу инфы зажравшимся владельцам скоростного безлимитного интернета с ахерительно мощным компьютером и разрешением монитора 100500 на 100500, котоых к слову маловато ссылка

Ну не знаю, не знаю…

Признаюсь, у меня на работе мощный комп, 2 больших монитора, быстрый инет, но все равно не вижу причин пренебрегать оптимизацией.
Недостаток алгоритмов генерирования изображения «на лету», в том что если пользователь откроет какую-нибудь страницу с очень большим кол-вом ещё не созданных картинок, то сервер подвиснет. Кроме того, в любом случае заставлять пользователя ждать генерации картинки — нехорошо.
Идеальное решение — совмещённое:
1) Имеем очередь картинок, которые нужно обработать.
2) Обработка картинок происходит по CRON (Берём N-картинок из очереди).
3) При добавлении в админке — добавляем картинки в очередь (можно сразу же запустить обработку принудительно).
4) Если пользователь запрашивает размер, для которого не сгенерирована картинка — добавляем в очередь (желательно при этом, если сервер не занят уже обработкой, сразу же генерировать эти картинки, но опять же с ограничением кол-ва).
5) (опционально) Если в процессе нам нужны другие размеры для картинок — пополняем очередь изменения для всех картинок.
мое решение не совсем «на лету», демон отработает до захода пользователя
ваше решение имеет недостаток — слишком много вводить сущностей — и очередь, и обработчик очереди, и приниматель запросов на получение картинки.
Сорл очень медленный, он делает очень много лишних запросов в базу, а генерация страницы, на которой есть изображения не прошедшие ресайз ооочень сильно тормозят работу сайта.
Непонятно, зачем такие сложности? Вы так часто меняете формат выдачи картинок? Обычно достаточно бывает создания нужных размеров сразу при загрузке оригинальной картинки. Даже если у вас меняется формат выдачи, всегда можно один раз запустить скрипт, который нарежет нужных картинок и удалит неиспользуемые.
проект домашний, а это дает возможности экспериментировать с дизайном и введением новых элементов… и… да… приходится менять размерность картинок.
UFO just landed and posted this here
celery — это хорошо, но в случае если он будет нужен только для картинок — то проще обойдись чем, то самописным. А если возникнет потребность обрабатывать еще что-либо в фоне — то тогда проще переписать велосипед на celery.
Тем более, что при использовании celery потребуется править код сайта — добавлять задачу при загрузке картинки и добавлять задачу при удалении(смены) картинки.
Sign up to leave a comment.

Articles