Всем привет! В этой статье я расскажу как разрабатывали решение по автоматизации генерации картинок из шаблона. Сначала будет обоснование кейса и затем техническая часть решения.
Обоснование кейса
Не секрет что соцсети являются огромной площадкой для поиска аудитории что бы позитивно выделить свой материал в ленте сделать его узнаваемым и вызывающим желание кликнуть. нужно правильно оформить на странице The Open Graph тэги.
страница без og тегов выглядит довольно куцо в соцсети или мессенджере, просто строчка с текстом и всю информацию о том что внутри вы узнаете только перейдя по ней. Настроив og теги вы сразу же можете презентовать свой сайт. и сделать его узнаваемым и выделяющимся ещё до того как пользователь зайдёт к вам. Важной частью этой узнаваемости конечно является изображение. Хорошо если у вас лендинг и вам достаточно одной картинки на весь сайт. Но если у вас ресурс с огромным количеством контента то нужно как то разнообразить эти изображения и сделать уникальными, вооружившись пэинтом фотошопом можно без проблем сделать такую картинку, но процесс этот довольно рутинный и скучный и всё таки требует времени, но его можно автоматизировать. В этом месте и появляется задача генерировать такие изображения автоматически. Работая в charmer мы делаем проекты на высоком визуальном уровне и изображения для расшаривания в соцсетях и мессенджерах являются важной частью. Давайте перейдём к описанию решения.
Техническая часть
Все кто пытался редактировать изображения в коде, скорее всего сталкивался с imageMagick решение уже зарекомендовавшее себя, есть обертки под все популярные языки, до сих не теряет актуальности поддерживается и развивается. Позволяет делать магию с картинками, закрывает практически все потребности в обработке картинок. Что же не так с ImageMagick? Он невероятно сложен в использовании. Если нужно сделать относительно сложный визуал
Например как тут
то в imageMagick будет довольно тяжело всё это выстроить. Учитывая то что изображение для фона, не всегда подходят по размеру и пропорциям под итоговый вариант. И наложенный текст может быть любой длинны. Так же в тексте могут быть важные типографические контролы, например неразрывный пробел.
В общем достаточно сложно сделать какой то шаблон для изображений который будет собираться в imageMagick. Но существует уже отличное готовое и всем известное решение для верстки по шаблону это - HTML.
Как можно применять HTML и Headless browser можно увидеть на схеме ниже.
Первым делом создается знакомый всем rails разработчикам ERB template. По нему генерируется html файл и запускается headless browser, исполнение bash команд в руби реализовано в Kernel. Дальше браузер сохраняет скриншот в файл и готово. Мы получили результирующую картинку.
Производительность
Запуск внешнего приложения в коде звучит как задача которую нужно явно запускать в фоновом режиме. Для этой цели отлично подходит sidekiq. Возможно у вас chrome тоже вызывает устойчивую ассоциацию с избыточным потреблением памяти, но как показали тесты, в headless режиме память расходуется в щадящем режиме.
На видео видно потребление ресурсов при работе приложения. Заметно как резко подскочило цпу, но это настраивается уже через sidekiq на видео в нем паралельно запускаются несколько воркеров, код для генерации картинок потокобезопасный. Если настроить на один поток то потребление ресурсов будет гораздо скромнее. За 20 секунд сгенерировалось и сохранилось 50 изображений, что достаточно быстро для такой задачи.
Итоги
Конечной целью было создание инструмента который позволит решать описанную задачу быстро и надежно. При написании кода упор был сделан на минимальное конфигурирование, потокобезопасность и простоту в использовании. Исходники доступны на гитахбе и сам гем на rubygems. Если для кого то этот гем будет полезным и найдутся идеи и желание как то улучшить\исправить с радостью приму PR или комментарии) Всем спасибо, кто дочитал до конца!
lexaploskov
Можно было использовать svg. И вы бы получили возможность перевода изображения в другие форматы.
viktar1 Автор
headless chrome кажется только в формате png делает скрин(