Почему это важно?
На современных web сайтах объем картинок может составлять от 30% до 70% всего размера страницы. Например, объем изображений на Хабре обычно составляет несколько мегабайт.
Большинство изображений в Web'e — это фотографии. Профильные фото в соц. сетях, альбом с телефона, профессиональные снимки и т.п. Правильная стратегия и инструменты для работы с фотографиями позволят сделать сайт быстрым для посетителей.
Формат для фотографий
Основной формат для хранения фотографий в Web'e — это JPEG. Однако иногда следует использовать и другие форматы.
JPEG
Хорошо подходит для сложных изображений, т.е. как раз для фотографий. Основной принцип сжатия в этом формате — это уменьшение качества путем уменьшения детализации изображения.
Подбор показателя сжатия может уменьшить размер исходного файла в несколько раз без заметного ухудшения качества. Логика такая: чем ниже качество — тем легче файл. Обычно используют показатель качества от 80 до 90.
Webp
Это формат, разработанный специально для обслуживания изображений в Web'e. Может уменьшить размер файла в несколько раз без потери качества. Значительно лучше сжимает фотки, чем JPEG. Однако поддерживается еще не всеми браузерами.
PNG и GIF
Эти форматы не подходят для фотографий. PNG изображения сохраняются без потери качества и лучше всего подойдут для иконок и графики. Формат GIF имеет ограниченную палитру, однако поддерживает анимацию.
Загрузка фотографий на сервер
Если на вашем проекте существует необходимость загружать пользовательские фотографии, сначала необходимо выбрать принцип их хранения на сервере.
Если вы собираетесь работать с сотнями файлов, стоит выбрать древовидную структуру:
Это позволит избежать ситуации с тысячами файлов в одной папке (это тормозит работу файловой системы и вашу собственную). Лучше всего использовать вложенную структуру из папок длинной в два символа:
$photo = $_FILES['image']['tmp_name'];
$name = md5($photo) . '.jpg';
$dir = substr(md5(microtime()), mt_rand(0, 30), 2) . '/' . substr(md5(microtime()), mt_rand(0, 30), 2);
$path = $dir . '/' . $name; # по этому пути сохраняем фотку
Инструменты
После загрузки фотографий на сервер, их следует обработать:
- Уменьшить размер до приемлемого. Нет смысла хранить и показывать оригинал фотографии размером 4000х3000 на сервере.
- Удалить все метаданные. Иногда объем такой инфы может составлять больше половины веса самого изображения.
- Провести оптимизацию для уменьшения размера файлов. Это ускорит загрузку у посетителя.
Для этого существует ряд инструментов.
ImageMagick
Сразу после загрузки фотографии на сервер, имеет смысл удалить все метаданные и изменить размер до 1000х1000:
# 90 - уровень сжатия в итоговом JPEG файле
convert input.jpg -strip -resize 1000x1000 -quality 90 output.jpg
GraphicsMagick
То же самое с помощью более производительного GraphicsMagick:
# изменение размера до 600х500 с уровнем качества в 90
gm convert input.jpg -strip -resize 600x500 -quality 90 output.jpg
Jpegtran
Этот инструмент уменьшает размер JPEG файлов без потери качества.
jpegtran -copy none -optimize -outfile min.image.jpg image.jpg
cwebp
Утилита позволяет преобразовать изображение в формат Webp.
cwebp -q 85 input.jpg -o output.webp
Отдача клиенту
Фотографии лучше всего отдавать Nginx'ом. Обязательно нужно настроить Cache-control и Keepalive для повышения скорости загрузки страниц:
http {
...
keepalive_timeout 75s;
server {
listen 80;
location ~ .\.jpg$ {
expires max;
}
}
}
Превью (thumbnails)
Часто нужно иметь возможность показывать небольшие версии фотографий (например, миниатюра профильной фотки).
Для этого необходимо генерировать нужные размеры при загрузке:
convert file.jpg -resize 50x50 file.s.jpg
convert file.jpg -resize 250x250 file.m.jpg
Тогда у каждого изображения будет соответствующая миниатюра.
Более удобный подход — генерировать превью на лету с помощью, например, Nginx image_filter модуля.
Поддержка Webp
Webp не поддерживается всеми браузерами, однако постепенно набирает популярность. Для того, чтобы извлечь пользу из этого формата, можно отдавать разные версии фотографий в зависимости от браузера посетителя.
Для каждой фотографии нужно сгенерировать webp версию:
cwebp file.jpg -o file.jpg.webp
Теперь необходимо отдать соответствующую версию картинки в зависимости от поддержки этого формата браузером:
server {
...
location ~* ^/.+\.(jpg|jpeg)$ {
if ($http_accept ~* "webp") {
rewrite (.+) $1.webp;
}
}
...
}
Облака
Облачные технологии развиваются и дешевеют. Если у вас нет специфических задач по обработке фоток, лучше присмотреться к варианту использования внешнего сервиса для их хранения и отдачи.
Amazon s3
Это облачное хранилище с которым не придется думать о масштабировании. Храните терабайты и не парьтесь. Пример реализации загрузки фотографий на S3 в PHP:
$path = 'photo_name.jpg';
$s3 = new S3('ключ', 'секрет');
$s3->putObjectFile($_FILES['image']['tmp_name'], 'букет', $path, S3::ACL_PUBLIC_READ, []);
После этого можно показывать фотку прямо с Амазона:
...
<img src="https://s3-eu-west-1.amazonaws.com/букет/photo_name.jpg"/>
...
Cloudinary
Мощный сервис для работы с фотографиями в облаке. Ресайз, кроп, распознавание лиц, разные форматы, онлайн редактор и другие функции.
i.onthe.io
Мега простой сервис, распознает возможности браузера и подбирает оптимальный формат отдачи. Поддерживает URL API для ресайза и кропа.
Конспект
- Правильный формат и сжатие фоток могут сэкономить до 70% объема страницы.
- Используйте только JPEG для фотографий.
- При возможности включайте поддержку Webp.
- Imagemagick, Graphicsmagick и Jpegtran для манипуляций и оптимизации фоток.
- Рассматривайте облачные решения для хранения фоток — это быстро и удобно.