JPEG стиск зображення з альфа-каналом або SVG masks

Передісторія

Якийсь час тому, коли про HTML5 мало хто знав, а flash був досить поширений, мені довелося вивчити ActionScript і робити красиві «іміджеві» сайти. Зазвичай такий сайт був досить насичений картинками, і більше, для деяких ефектів потрібно використовувати фотографії з прозорим тлом (наприклад, коли товарна одиниця з тінню красиво вилітає звідки по неоднорідному тлі). Але як відомо JPEG не дозволяє зберігати в собі альфа-канал, а PNG - це формат стиснення без втрат, через що розмір такого фото виходив м'яко кажучи більшим. У flash ж можна було зберегти напівпрозорі зображення з JPEG-компресією, досягалося це тим, що альфа-канал зберігався окремо від зображення, отримуючи два зображення, які згодом зберігалися в JPEG. Пізніше верстаючи один із «звичайних» html-сайтів, мені також знадобилося зберегти велике неоднорідне напівпрозоре тло, але ні збереження в png-32, ні в png-8 не давали прийнятний результат - png-8 виглядав огидно, а png- 32 важив надто багато. У пошуках технології, яка дозволила б зберігати зображення з альфа-каналом зі втратою якості, я натрапив на SVG Mask.

То навіщо це потрібно?

Візьмемо гіпотетичний приклад - потрібна нам ось-така картинка з «діркою» всередині: (3-32, 1870 Кбайт)

Стиснення в 256-ти кольорову палітру PNG-8 «вбиває» зображення:

альфа-каналом
(PNG-8, 305 Кбайт)

Тоді як застосовуючи flash ми отримаємо swf скромного розміру, при цьому на око мало від оригіналу: flash (swf, 453 Кбайт)

В принципі, якби не складнощі із зручністю генерації swf, і не повної підтримки flash на всіх пристроях, можна було б на цьому закінчити. Але є зручніша HTML5 альтернатива!

Суть методу

Сам методне нове і зрідка зустрічається його опис на деяких ресурсах. Але, на жаль, інформації про нього відносно мало, принаймні на хабрі статті не знайшов, що поспішаю поправити. Стандарт SVG дозволяє впроваджувати в себе растрові зображення, а також дозволяє застосовувати маски. Так чому ж нам не реалізувати так само, як і у flash? Виділяємо альфа-канал і зберігаємо його в окремий файл:

альфа-каналом
стиск
(JPEG, 165/46 Кбайт)

Сумарний обсяг вийшов навіть меншим, ніж .swf - 211 Кбайт!

Як варіант можна впровадити файли прямо в svg (зменшуємо кількість запитів), за допомогою data: URI, правда в цьому випадку розмір зросте в середньому на 33%, хоча це можна обійти за допомогою gzip-стиснення. приклад.

Як на рахунок кросбраузерності?

Свого часу я цей метод залишив на «світле майбутнє», тому що тоді підтримка SVG браузерами була не дуже, та й замовники з вимогами до ie6 ще залишалися, але час іде, і зараз вже можна застосовувати цей метод у «бойових умовах» ». Про впровадження SVG у HTML вже були статті на хабрі: раз, два, тому особливо докладно зупинятись на цьому питанні не буду. Крім того ви можливо помітили, що прописав-webkit-background-clip: text;, це потрібно для прозорості об'єкта, що впроваджується, в старих safari і chrome (у сучасних версіях цей баг вже закрили). Але як бути з ie7, ie8? Для цієї «вмираючої» аудиторії ми можемо запропонувати flash, а якщо і його немає, то, на крайній край, нехай вантажать важкий PNG-32 (або якусь заглушку).

Почнемо з того, як підключати SVG? Для огляду різних методів впровадження SVG, я зробив спеціальну демо-сторінку.

jpeg

Таким чином, ми можемо істотно скоротити розмір зображень. Цей метод протестований на ie7-ie9, firefox 13, chrome 19, opera 12, Safari5 (win), Android 2.3. Прохання протестувати його в інших браузерах. Дякую за увагу!

PS. Не вперше натикаюся на нерозуміння, що маска — це довільне зображення, круговий градієнт я використовував як приклад, насправді маска — JPEG-картинка, яка може бути будь-якою геометричною складністю!

Хардкорна конфа за С++. Ми запрошуємо лише профі.