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


Изображение для верхней части сайта

Речь идёт о подготовке изображения, рассчитанного на использовании в верхней правой части сайта jamstackconf.com. Мы, в маркетинговой команде Netlify, используем Figma. Первая моя попытка экспорта этого изображения для использования его на сайте оказалась далеко не самой удачной.

Попытка №1: SVG


Вот на какие примерные размеры изображения я вышел, экспортировав материалы в формате SVG:

  • 10,1 Мб — исходный SVG-файл, экспортированный из Figma.
  • 9,9 Мб — SVG-файл, оптимизированный с помощью инструмента SVGOMG.

Теперь я знаю, что это — размеры несжатых файлов (до применения к ним алгоритмов сжатия GZIP/Brotli). Но я уверен, что никто не станет со мной спорить о том, что изображение размером 9,9 Мб, пусть и оптимизированное, слишком велико даже для самого старательного алгоритма сжатия (Уточнение: после GZIP-сжатия 9,9 Мб превратились в 7,36 Мб). Учитывая то, что в этом SVG-файле имеется очень много встроенных растровых изображений, с помощью одного лишь SVGOMG как следует этот файл не сжать. Попробуем перейти к растровому изображению и узнать о том, насколько далеко в деле оптимизации изображений нас это может завести.

Попытка №2: PNG


  • 1,2 Мб — исходный PNG-файл, экспортированный из Figma.

Вы все знаете меня достаточно хорошо для того чтобы понять, что я не размещу картинку размером 1,2 Мб в очень важном месте страницы. Поэтому я решил заняться оптимизацией. Тут важно учитывать то, что мне надо было сохранить канал прозрачности. В результате, если изменится фоновый цвет страницы, не придётся снова оптимизировать изображение. Этот факт означает, что мы сразу же отказываемся от формата JPEG.

▍ImageOptim


  • 831 Кб — PNG-файл, оптимизированный с помощью ImageOptim.

Меня впечатлило то, что, после буквально одного движения мыши, ImageOptim убрал примерно 400 Кб данных из моего изображения. Но итоговые 831 Кб — это всё ещё слишком много.

▍Squoosh


  • 376 Кб — PNG-файл, оптимизированный с помощью Squoosh (с применением уменьшенной цветовой палитры, состоящей из 256 цветов).

Вот это уже похоже на что-то приличное. Опция уменьшения цветовой палитры Squoosh (Reduce palette) даёт огромный выигрыш в размерах готового изображения. Ещё я немного поэкспериментировал с параметрами формата AVIF в Squoosh, но формат PNG, всё равно, оказался лучше (Уточнение от 27 августа: обратите внимание на новый раздел с заголовком «Попытка №4: AVIF»).

Попытка №3: WebP


  • 152 Кб — WebP-файл, оптимизированный в Squoosh (сжатие без потерь, цветовая палитра уменьшена до 256 цветов).

Поразительная экономия! И этот вариант предусматривает использование тега <picture> для прогрессивного перехода с PNG на WebP. Многие могут решить, что этот результат уже «достаточно хорош», но всё то, ради чего я писал этот материал, ещё впереди (и то, что получилось, получилось, и правда, очень хорошо).

Попытка №4: AVIF


  • 168 Кб — AVIF-файл, оптимизированный в Squoosh (полная цветовая палитра).

Уточнение от 27 августа: Джейк Арчибальд дал мне хороший совет, который заключался в том, чтобы снова попробовать формат AVIF (но в режиме сжатия с потерями), не уменьшая цветовую палитру. Полагаю, что это — очень хорошая идея! Уменьшение цветовой палитры (хотя и даёт значительную экономию размера файла) определённым образом сказывается на готовом изображении. Моей неофициальной целью было получение AVIF-изображения как можно более высокого качества и сохранение при этом размеров файла на уровне WebP-версии с уменьшенной цветовой палитрой.

Вот — отличный материал Джейка про AVIF.

Этот вариант изображения получен при использовании следующих настроек Squoosh:

  • Lossless: выключено.
  • Quality: 45.
  • Subsample Chroma: выключено.
  • Effort: 6.

Победитель: два отдельных слоя: SVG + AVIF/WebP/PNG


  • 74 Кб + 4,2 Кб — оптимизированные SVG-файл и AVIF/WebP/PNG-файл

Если выделить те части изображения, которые хорошо описываются векторными инструментами (градиенты, линии и прочее подобное), и поместить их в SVG-изображение, а всё остальное сохранить в растровом формате, мы можем добиться даже лучших результатов. Пользуясь этим подходом, я, правда, сделал не всё, что было возможно. А именно, перенёс на векторный слой не всё, что можно было туда перенести. Возможно, кто-то решит, пользуясь таким подходом, оставить больше фрагментов изображения на переднем плане, например, на тот случай, если кто-нибудь захочет распечатать страницу (ну — это если кто-то до сих пор выводит веб-страницы на принтерах).


Два слоя изображения

Используя растровый слой как изображение переднего плана, а вспомогательное векторное изображение — в виде того, что задаётся в CSS-свойстве background-image, мы можем скомбинировать эти изображения. Можно даже вернуть оптимизированное растровое изображение обратно в формат SVG, в виде Data URI, внедрённого в <image>, но я так делать не стал.

Итоговые результаты


Тут показаны результаты вышеописанных экспериментов. Полагаю, то, что удалось прийти от исходного изображения размером более 10 Мб к изображению размером в 78 Кб, это — не так уж и плохо. Экономия рассчитана в сравнении с предыдущей попыткой.

Метод Размер Экономия
Исходный SVG 10,06 Мб
SVG, оптимизированный с помощью SVGOMG 9,92 Мб -0,14 Мб
PNG 1,16 Мб -8,76 Мб
PNG, оптимизированный с помощью ImageOptim 831 Кб -329 Кб
PNG, оптимизированный с помощью Squoosh (уменьшенная палитра) 376 Кб -455 Кб
WebP, оптимизированный с помощью Squoosh (уменьшенная палитра) 152 Кб -224 Кб
AVIF, оптимизированный с помощью Squoosh (полная палитра) 168 Кб +16 Кб
Два слоя: SVG (SVGOMG) и AVIF/WebP/PNG (Squoosh) 78 Кб -90 Кб

Как вы оптимизируете изображения для своих веб-проектов?

Комментарии (17)


  1. Aquahawk
    26.09.2021 17:46
    +3

    Люблю такие штуки. Как инженер. А как руководитель разработки - нет. Стоимость производства такого арта космическая. Внятно обучить этому дизайнеров, поставить на поток, чтобы стабильно получать подобный эффект по качеству нереально. Привлекать к этом разработчика смысла никакого не имеет. Лучше он что-то более полезное для бизнеса за это время сделает. Из практики по хоть сколько-то устоявшимся продуктам, которые привлекают пользователя, значимого эффекта на деньги от ускорения загрузки не замечено. Понятно что если продукт грузится минуту это жесть, и то не всегда, но начиная с определённых величин затраты на сокращение времени загрузки всё больше, а эффекта всё меньше. Что не отменяет красоты решения, а также того факта, что еще 15 лет назад во флеше так уже делали одним кликом(convert to bitmap) и более того, там нормально работал прозрачный jpeg в любой комбинации с вектором. Но уже тогда подобные рекомендации на поток нормально не ставились.


    1. DistortNeo
      26.09.2021 17:55

      Да, я бы остановился на экспериментах с WebP.
      Дальнейшие улучшения уже слишком трудозатратны и не оправдывают себя.


    1. rexen
      28.09.2021 10:16

      Тут именно что нужно "технико-экономическое обоснование". Одно дело - акционный лэндинг для местного сельпо, другое дело - какой-нибудь Алиэкспресс с миллионами закачек. В первом случае на художественных "приседаниях" можно и нужно экономить, т.е. не заморачиваться. Во втором - воевать за каждый байт. На практике каждый проект оптимизируется где-то на удобной конкретно ему середине.

      PS: хотя на фоне этих экономий считанных килобайтов иногда просто до слёз обидно видеть в статьях даже на Хабре иллюстрации в статье весом под десяток МегаБайт - люди (технари!) прямо со своих многомегапиксельных айфонов вываливают фотки непосредственно в статью - банально ни ресайза, ни кропа... я уж не говорю про какую-то там оптимизацию.


      1. Aquahawk
        28.09.2021 10:28

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


  1. i360u
    26.09.2021 19:36
    +4

    Какой ерундой люди готовы заниматься, лишь бы не открывать SVG в текстовом редакторе...


    1. Moskus
      26.09.2021 22:25

      Справедливости ради, это ещё и отличный пример (независимо от технической сложности задачи), чего не стоит делать с точки зрения дизайна. Все эти микро-физиономии людей, которых никто не знает, снятые веб-камерой во время zoom-встречи не должны были появиться в макете вообще.


  1. mSnus
    27.09.2021 05:12
    +1

    Сохранили бы в JPEG и не мучились. Изменится фон сайта? Ну, придётся переделать JPEG, займёт минуту.


    1. rexen
      28.09.2021 10:08

      Кстати, с нынешней модой на light/dark - темы сайтов иногда так и приходится делать - по два набора оформительской графики - для тёмной и для светлой схемы.


  1. SquareRootOfZero
    27.09.2021 09:28
    +2

    Давно делаю что-то подобное для подписей к картинкам. Я не веб-дизайнер и не мастерю сайты, но иногда бывает нужно взять фотографию и где-то понадписывать текста, подрисовать тонких аккуратных стрелочек и вот этого всего. Если результат сохранить в jpeg, текст и линии превращаются в говно, если в png — размер опухает в десятки раз. Остановился на формате («сам придумал») SVG, когда в одном слое jpeg-фотография, в слое поверх — png с текстом и стрелками (можно бы, наверное, оставить их в векторном представлении, но для простоты и автоматизации png вполне хватает), оба слоя кодируются в base64 и встраиваются в SVG-файл, результат выглядит как-то так:

    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <image href="data:image/jpg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDABALDA4MCh..."/>
    <image href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA88AAAMrCAYAAAB3Xq..."/>
    </svg>

    Размер файла практически идентичен сумме исходных файлов, процесс изготовления тоже довольно прост (открыл картинку в первом слое, нарисовал подписи во втором слое, удалил первый слой, экспортировал все в png, простеньким самописным скриптом сконвертировал в вышеприведенный SVG (возможно, есть проще способы, без скриптов, но я не дизайнер, у меня Gimp и лапки). Что не радует — это что всякие дефолтные графические просмотрщики такое открывают плохо или не открывают вовсе, и в какое-нибудь корпоративное вики оно тоже не встраивается как изображение — сперва качай файл, потом у себя отдельно открывай браузером.


    1. Akon32
      27.09.2021 10:20

      Подобные идеи разделения текста и картинок лежат в основе формата djvu. Но вместо png там - более агрессивные методы сжатия бинарных изображений текста.

      И результат - около 60кб на скан страницы А4.


    1. mSnus
      28.09.2021 14:16

      Вообще есть такой универсальный формат - pdf, в нем подобные случаи как раз предусмотрены. Но если для себя -- да, отличное решение.


      1. SquareRootOfZero
        28.09.2021 15:06

        Самый главный вопрос — «универсальный формат pdf» можно вставить в веб-страницу не как что-то инородное, а как обычное изображение, без всех этих вот отдельных встроенных оконцев, виджетов и гаджетов?

        И второй вопрос — каким достаточно простым и бесплатным софтом такой pdf можно изготовить? Из того, чем я обычно пользуюсь — Gimp сделал как-то криво, к тому же, файл таки опух со 100 Кб до мегабайта; Inkscape экспортировать в PDF не дает вообще; самому писать скрипт — как-то уныло, в отличие от SVG за пять минут левой ногой не сделаешь.

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


  1. Tenebrius
    27.09.2021 10:28

    Судя по двум последним картинкам (Вектр + Раст), растровую часть тоже вполне можно было перевести в вектр. Там логотипы и текст, а они и так почти всегда в векторном виде.


  1. starcs
    28.09.2021 12:00
    +4

    Решил провести исследование и скачал эти файлы сайта. Учтем, что у меня не исходники и они уже оптимизированы.

    Если открыть .svg файл в Photoshop, то узнаем, что его размер 3721х3721 пикс. Открыв .png - 1786х1786 с прозрачным полем, т.е. он уже меньше сам по себе.

    Увеличиваем png до размеров svg (как на сайте). И теперь наложим два файла в редакторе в соответствии с сайтом. Градиент делаем растром - изначально по тексту он был таким. А для чистоты эксперимента изменяем цвета, накладываем шум, вносим хаос в оптимизированное изображение.

    Успешно получаем примерно такие же размеры файлов или даже хуже - svg с растром более 13 мб, png с градиентом около 3-х мб. Опять же разные алгоритмы сжатия и само качество изображения хуже. Средний размер jpeg такого же размера (5000х5000 пикс) будет примерно 4-5 мб.

    Получаем: разработчики сами экспортировали файл из Figma, получили svg со встроенным битмэпом 4х4 тысячи пикселей весом в 10 мб и поняли что что-то пошло не так. И начали решать проблему сами, вместо того, чтобы озадачить ответственных. Или их нет и делал дизайн индус-фрилансер, который ушел в закат. А дальше начались шаманские пляски с бубном. И на каком-то этапе они изменили размеры в пикселях и убрали градиент, который давал большое увеличение веса файла, плюс оптимизация цвета. Скорее всего достаточно было на первой попытке открыть векторный файл в векторном же редакторе, увидить кривой битмап и далее по списку.

    А вывод какой? Не в оптимизации сайта, а во взаимодействии между отделами. Точнее, его отсутствии.

    У меня png без оптимизации (с градиентом и сеткой) получился около 0,8 мб, jpeg с фоном как на сайте 0,7 мб. Это без каких либо ухищрений. А так при желании тут все изображение можно сделать svg, кроме 5 мелких фото. Такой вот реверс-инжиниринг в дизайне.


    1. mSnus
      28.09.2021 14:19

      Добавлю только, что под Windows нормально выдавать SVG умеет только Inkscape: и Photoshop, и Illustrator делают обычно что-то адское с файлом.


      1. starcs
        28.09.2021 15:13

        Photoshop с вектором вообще в полной мере плохо работает. Даже при экспорте в формат Illustrator.


  1. sim31r
    29.09.2021 01:38

    Ну можно пойти еще дальше, уже только теоретические методы.

    Разработать исполняемый файл, для генерации исходного изображения. Фон кажется можно создать алгоритмически, квадратная сетка и градиент синего. Десяток строк кода.

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