Pull to refresh

Как я png в 4 раза уменьшал

Reading time4 min
Views23K
Эта идея возникла год назад, когда мне на просчет пришел проект веб-игры с большим количеством анимации, которую предполагалось делать спрайтами в хорошем качестве (большими спрайтами) и с качественным альфаканалом (в смысле, не с индексированным цветом прозрачности). В этой игре вы бросаете кости на стол и надо, чтобы они падали всегда по-разному.

Сделать одну такую png-анимацию размером одного кадра 400 на 400 мне, как в том числе аниматору, не составляло труда. Сделать сбрасывание кубиков всегда разным представлялось задачей нетривиальной ни в одном месте. Однако замотивированный круглой суммой из волосатых рук я начал штурм, думая в первую очередь о том, как сделать игру одновременно и красивой (так как изначально я дизайнер, трехмерщик и эстэт, а программистом не стану никогда), и такой, которая загрузится меньше чем за тысячу минут.

Желая оценить объем графических файлов анимаций, я сделал вариацию падения одного кубика в полоске, чтобы потом сбрасывать несколько подобных вариаций под разными углами и, возможно, это было бы достаточно разнообразно. Когда я собрал секвенцию кадров в горизонтальную полоску, мысль о GIF, его горизонтальным сжатии и индексированных цветах зажглась сразу же и отпустила только вчера вечером.

По своему опыту специалиста по анимации трехмерных кубиков я знаю, что пока они скачут и всячески анимируются, важность качества отображения их краев и других деталей обратно пропорциональна скорости. Поэтому где-то их можно пожать по максимуму как в альфе, так и в rgb, а на кадрах, где движение успокаивается и кубик встает – делать уже на 100%. То есть png со своими огромными размерами востребован только в последних 5-10 кадрах из 50-кадровой секвенции – и только в том месте кадра, где остановился кубик. Желание пожать все, что можно, напрашивается само собой.

throw

Делая вариацию падения кубика я допустил, что потом для него можно будет сделать один альфа-канал и шесть rgb-вариантов с разными текстурами (разными финальными значениями кубика). Пока кубик летит, он летит по прямой, после первого удара он чуть отклоняется, а потом отклоняется сильно, поэтому полоска кадра получается не такой тонкой, как хотелось бы, и большая часть каждого кадра остается пустой, что болезненно для png, но не было бы проблемой для gif. В итоге со всеми ухищрениями на один вариант в формате png32 потреблялось полмегабайта килобайтов. Это не учитывая, что таких вариаций падения надо было еще, скажем, штук 10 хотя бы, и в игре ожидалась куча другой графики.

Но вдруг!


В тот момент, когда я уже вошел во вкус какие-то прекрасные люди предложили заказчику сделать заказ на 7 копеек меньше и заказ сбрился, а все написанное выше лишилось логического конца. Неприятно, да? Однако я остался с пониманием четко очерченной проблемы: альфа-канал в современных больших и красивых изображениях используется подчас до безобразия расточительно и с пониманием как эту проблему можно решить.

Я подождал год, потом сел, нашел эту статью, взял из нее весь код, вставил в случайные места точки с запятой и получился javascript-плагин, который может творить, согласно моему воспаленному воображению, чудовищные вещи с анимацией на сайте, уменьшить трафик полноцветных RGBA изображений в 2-10 раз и перевести использование больших RGBA изображений на сайте в плоскость разумного. Также в него сразу зашита функция нарезки на спрайты, поэтому он может оказаться полезен для тех счастливцев кто озабочен front-end оптимизацией.

upd
По итогам публикации и комментирования стал понятен оптимальный вариант применения плагина: по причине того что он обрабатывает изображения в ходе загрузки страницы, он будет особенно интересен для тех, кто использует карты спрайтов или анимации с прозрачностью и заморачивается предобработчиком этих карт спрайтов, а так же тем, кому нужны true-большие изображения с прозрачностью и возможностью крутить степень сжатия. Для единичных и небольших картинок подойдут тинипнг и схожие сервисы.

Матчасть


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

В ходе загрузки страницы вызывается функция alpha_spriter и в нее подаются 4 атрибута:

  1. URL rgb-файла со спрайтами
  2. URL соответствующего файла с альфа-каналом в опять же любом формате, в большинстве случаев это gif / png8.
    Оба файла должны быть на этом же домене.
  3. Javascript-объект вольной формы с разметкой спрайтов. Шутка! (заметили?) Форма достаточно точна и её пример доступен в коде плагина.
  4. Ну и функция, какую хотите по завершению

В ту же секунду функция загружает изображения, совмещает их с помощью canvas в полноценный png32 и режет на спрайты. На выходе сгенеренные изображения назначаются по id (указанным в объекте JS), заготовленным в теле документа элементам в двух вариантах: src для <img>, либо background-image (поверх уже установленных других необходимых свойств фона).

Минимальная первая рабочая версия незамедлительно опробована и успешно совмещает на живом проекте изображение танцующего снежного барса, местами напоминающего петуха и таким образом спасает it-инфраструктуру одной страны от необратимого перегрева.

compare

Прилагаю для сравнения хронометраж загрузки страницы. Сама страница, плагин и тестовые файлы могут быть найдены на гитхабе, если это здесь не запрещено. Если запрещено – просто не нажимайте, пожалуйста.

time

На всякий случай еще раз обратите внимание, что у меня канвас делал свое дело в условиях веб-окружения и только со своего origin. Этот момент уточняется.

Всё


А теперь расскажите мне, что таких решений уже 10 и они никому не нужны. Про rgb8 и про альфу в css. Ну а если серьезно, то хотелось бы в первую очередь понять, насколько это востребовано и в случае чего допиливать до уровня hi-end 3000 и делать генератор sprite map. Ну и, собственно, если у вас есть пожелания – велкам.

Спасибо!

Список литературы


Та самая статья, послужившая ускорению разработки плагина и, возможно, обусловившая его появление — спасибо, sergof!
Tags:
Hubs:
Total votes 24: ↑22 and ↓2+20
Comments13

Articles