Всем привет! Сегодняшний пост посвящен производительности при обработке изображений. Почти в каждом проекте требуется обработка изображений, например, ресайзинг, поворот, обесцвечивание и т.д. Для этих целей я использовал широко известное решение, написанное на php и работающее с расширением GD - class.upload.php. До тех пор пока в проектах в основном изображения загружались через админку меня это решение полностью устраивало. Но в одном из последних проектов изображения являются одним из главных видов контента и загружаются пользователями в больших объемах. При профилировании я заметил что процесс ресайзинга и обработки изображений занимает очень много времени. Особенно это бросалось в глаза при использовании функции "повернуть изображение", которая должна делать ajax-запрос и отображать повернутое изображение пользователю. При достаточно большом разрешении изображения скрипт падал по timeout не успев вложиться в 30 с в других случаях была очень большая задержка. Далее я опишу каким образом была решена данная проблема и предоставлю несколько результатов тестов для сравнения.
Выбор инструмента
Очевидным решением было перенести данный функционал на консольную утилиту. Мой выбор пал на GraphicsMagick, т.к. данная утилита реализует все необходимые мне функции и при этом достаточно проста в использовании и хорошо документирована. Для установки в debian необходимо выполнить:
apt-get install graphicsmagick
Запуск выполняется при помощи команды gm. Рассмотрим несколько примеров использования.
Конвертирование изображений.
gm convert -quality 80 input.png output.jpg
Утилита выполнит конвертирование файла input.png в формат jpeg и сохранит как output.jpg. При помощи опции -quality выставляем качество выходного изображения в стандартной для jpeg форме.
Ресайзинг
Ресайзинг с установленной шириной (300px) и автоматически выбранной высотой с сохранением соотношения сторон:
gm convert -resize 300 input.jpg output.jpg
Ресайзинг с установленной высотой (200px) и автоматически выбранной шириной:
gm convert -resize x200 input.jpg output.jpg
Ресайзинг без сохранения пропорций:
gm convert -resize 300x200! input.jpg output.jpg
Ресайзинг с сохранением пропорций и вписыванием в заданный размер по большей стороне:
gm convert -resize 300x200 input.jpg output.jpg
Ресайзинг с сохранением пропорций и вписыванием в заданный размер по меньшей стороне:
gm convert -resize 300x200^ input.jpg output.jpg
Ресайзинг с сохранением пропорций, вписыванием по меньшей стороне и обрезкой лишнего с центированием:
gm convert -resize 200x300^ -gravity center -crop 200x300+0+0 input.jpg output.jpg
Поворот
gm convert -rotate 90 input.jpg output.jpg
Поворачиваем изображение на 90 градусов. Также можно задавать отрицательные значения, чтобы поворачивать против часовой стрелки.
Параметры можно комбинировать, что значительно упрощает выполнение сложных операций
Бенчмарк
Теперь, как и обещал, немного цифр. Сравним производительность php решения (class.upload.php) и утилиты GraphicsMagick.
Конвертирование изображений
Конвертируем 40 Mb изображение из png в jpeg.
Время (с) | |
---|---|
upload.class.php | 97.150 |
GraphicsMagick | 3.304 |
Ротация изображений
Поворачиваем изображение (jpeg файл 6.4 Mb) на 90 градусов.
Время (с) | |
---|---|
upload.class.php | 162.750 |
GraphicsMagick | 2.6597 |
Нарезка thumbnails
Нарезка 5 thumbnails различной конфигурации из jpeg файла 6.4 Mb.
Время (с) | |
---|---|
upload.class.php | 12.010 |
GraphicsMagick | 4.594 |
Выводы
Результаты теста вполне ожидаемы и из них можно сделать выводы, что обрабатывать изображения средствами php следуют только в крайних случая. Например, если вы используете shared hosting или если изображения добавляются не часто и только через админку. Также к плюсам upload.class.php можно отнести простоту в использовании, т.к. он предоставляет удобный класс со всеми необходимыми методами, но написать небольшую объектную обертку для GraphicsMagick я думаю не составит труда.