Недавно передо мной встала задача обрезать около сотни огромных картинок из фотобанка под несколько десятков разных размеров. Эти готовые картинки потом будут использоваться клиентами CMS для оформления своих сайтов. Прикинув сколько времени займет этот процесс в Фотошопе, я пригорюнился — встретить следующий Новый год за обрезкой картинок не входит в мои планы.
Идея
Немного «пораскинув» мозгами, я пришел к выводу, что надо ввести понятие точки фокуса и учитывать ее при обрезке. Если пропорции нового изображения близки к исходным, например, мы вырезаем из квадрата прямоугольник с соотношением сторон 3:4, то вообще все замечательно, — новое изображение даже не потеряет в композиции. Если размер нового изображения отличается разительно, например, это узкая полоска для слайдера, то как минимум сохраним наиболее значимую информацию. Не забывайте, речь все таки идет об автоматической обрезке.
Вот иллюстрация, для демонстрации механизма.
Итак, точка фокуса — это точка в центре области, содержащей самую важную часть изображения, и которая при обрезке должна остаться в любом случае. Для рядовой фотографии в эту область будет сфокусирован объектив при съемке, особенно хорошо это видно, если съемка велась с малой глубиной резкости. Отсюда, собственно, и название для понятия.
Я решил проверить свои умозаключения и поискать не сделал ли кто-нибудь уже что-то подобное. Нашлась HTML/CSS библиотека для адаптивной обрезки изображений github.com/adamdbradley/focal-point. Тут тоже используется понятие «точки фокуса», значит моя идея верна! Но мне нужна была готовая утилита, которая сможет генерить физические изображения. Такой найти не удалось.
Реализация
Тогда я взялся за Node.js, который хоть и не является моим постоянным рабочим инструментом, но который я очень люблю использовать для автоматизации и небольших утилит.
Алгоритм обрезки нового изображения получился следующим:
- Вычисляем пропорции конечного изображения:
k=Wr/Hr
,
где Wr и Hr — ширина и высота будущей картинки - Определяем максимальный прямоугольник, который впишется в оригинальное изображение:
if Wr >= Hr
then Wm = Wi, Hm = Wi/k
else Hm = Hi, Wm = Hm*k
,
где Wi, Hi — размеры оригинала, а Wm, Hm — размеры максимального прямоугольника. - Вычисляем новые координаты для точки фокуса:
fx2 = fx*Wm/Wi
,
fy2 = fy*Hm/Hi
,
fx, fx — координаты точки фокуса на оригинальном изображении - Делаем собственно обрезку, смещая прямоугольник на разницу между старыми и новыми координатами точки фокуса:
crop(Wm, Hm, (fx-fx2), (fy-fy2))
- Уменьшаем результат до нужного размера:
resize(Wr, Hr)
Для обработки изображений я взял модуль GraphicsMagick for node, потому что она обещала беспроблемную работу с графическими библиотеками под Windows. И почти не соврала. ImageMagick вместе с ней мне так и не удалось запустить (причем более старый модуль imagemagick-node работал без проблем), а вот альтернатива в виде GraphicsMagick заработала сразу и без шаманства. Теоретически на другой платформе должен заработать и ImageMagick, какой-то жесткой привязки к библиотеке в модуле gm нет.
В итоговую утилиту я добавил немного оптимизации для веба: из итоговой картинки вырезается вся EXIF, ICM и пр. информация и полученное маленькое изображение прогоняется фильтром резкости. При уменьшении с 3000х4000px до 200x300px это действительно необходимо.
Для удобства работы исходные данные принимаются в виде 2 файлов:
- formats.json — файл, в котором перечислены форматы в который нужно обрезать
- images.json — файл, в котором перечислены изображения и заданы точки фокуса. Здесь же можно задать куда и в каком качестве сохранять картинки.
Подробное о форматах файлов, установке и дополнительных возможностях можно почитать в репозитории на GitHub github.com/fetis/fcrop. Там же можно найти демку для примеров.
И напоследок, пример работы утилиты
Ссылка на оригинальное изображение 5.4 Mб
200х135
500х180
900х172
Автор: fetis26