SVG-фильтры — это воистину мощный, но при этом очень редко используемый инструмент. A все потому, что многие до сих пор испытывают страх перед SVG в целом, а уж фильтрация и эффекты кажутся чем-то специфическим и трудным для изучения.
В этой статье я попытаюсь убедить Вас в обратном, расскажу о возможностях и типах SVG-фильтров и, в частности, о том, как применить их к изображениям на веб-страницах.
SVG-фильтры поддерживаются почти всеми современными браузерами, включая мобильные. Исключение составляют IE9 и Android native browser версии ниже 4.4.
svg-filters поддержка браузерами
Чтобы понять, что представляет из себя фильтр в SVG, давайте разберем простой пример. Для начала мы нарисуем круг:
<svg width="400" height="300" viewbox="0 0 400 300">
<circle cx="200" cy="200" fill="#3498db" r="80" />
</svg>
Если Вы вообще не знакомы с SVG, то сейчас самое время познакомиться :)
Вкратце:
- тег
<circle>
— это круг - аттрибуты
cx
,cy
— задают положение центра круга,fill
— заливку,r
— радиус.
То, что мы написали, будет выглядеть в браузере вот так:
Да, круто. Настоящий, большой и синий SVG-круг. А теперь давайте опишем простейший SVG-фильтр, задающий гаусовское размытие, и применим этот фильтр к нашей незамысловатой фигуре.
<svg width="400" height="300" viewbox="0 0 400 300">
<defs>
<filter id="myFilter1">
<feGaussianBlur stdDeviation="10"/>
</filter>
</defs>
<circle cx="200" cy="150" fill="#3498db" filter="url(#myFilter1)" r="80" />
</svg>
Сам фильтр определяется в секции <defs>
с помощью тега <filter>
. Ему необходимо задать id (уникальный в контексте всего документа). У нас это id="myFilter1"
.
Внутри описываются типы применяемой фильтрации. В нашем примере это <feGaussianBlur>
, где атрибут stdDeviation
регулирует уровень размытия.
Забегая вперед, скажем, что спецификация определяет несколько типов фильтрации с большим количеством возможных атрибутов для настройки их параметров.
Далее к той части SVG, которая должна быть обработана фильтром, нужно добавить атрибут filter="url(#myFilter1)"
с указанием id фильтра.
И вот что получится:
Да! Вот он — наш первый SVG-фильтр. Не так сложно, как казалось, не правда ли? Идем дальше. Давайте применим такой же фильтр к растровой картинке. Для этого поместим изображение красивой девушки в наушниках внутрь SVG:
<svg width="400" height="300" viewbox="0 0 400 300">
<image width="100%" height="100%" xlink:href="/blogdemo/img/girl.jpg" />
</svg>
И применим к изображению фильтр, описанный выше:
<svg class="cover" width="1024" height="768">
<defs>
<filter id="myFilter2">
<feGaussianBlur stddeviation="5" />
</filter>
</defs>
<image filter="url(#myFilter2)" xlink:href="/blogdemo/img/girl.jpg" width="100%" height="100%" />
</svg>
Получилась «разблюренная» девушка, как мы и ожидали. И это только начало. Продолжаем!
Комплексные SVG-фильтры. Применяем несколько эффектов последовательно.
Еще одним неотъемлемым достоинством SVG-фильтров является возможность сочетания нескольких типов фильтров. Т.е. результат, полученный после применения одного фильтра, может являться источником изображения для другого фильтра и т.д.
Чтобы было понятнее, давайте добавим еще один тип фильтрации для «разблюренной» девушки. Например, сделаем изображение черно-белым.
<svg width="400" height="300" viewbox="0 0 400 300">
<defs>
<filter id="myFilter3">
<feGaussianBlur in="SourceGraphic" result="a1" stddeviation="3" />
<feColorMatrix in="a1" type="saturate" values="0"></feColorMatrix>
</filter>
</defs>
<image filter="url(#myFilter3)" xlink:href="/blogdemo/img/girl.jpg" width="100%" height="100%" />
</svg>
Графически эту схему фильтрации можно представить как:
Как Вы видите, для каждого типа фильтров можно указать атрибуты in
и result
. Если они не указаны, фильтры будут применяться последовательно в порядке их записи.
В качестве in
для первого типа фильтра по умолчанию используется предопределенное значение SourceGraphic
(в нашем случае оно является псевдонимом <image>
)
Типы SVG-фильтров
Как мы уже говорили, существует несколько возможных типов фильтров. Давайте разберем каждый из них подробнее. Для простоты восприятия мы будем рассматривать только код, находящийся внутри тега filter
. Все остальное остается таким же, как в предыдущих примерах.
feComponentTransfer
Фильтр <fecomponenttransfer>
позволяет производить линейные, табличные, дискретные операции над каналами изображения, а также изменять гамму каждого канала.
Давайте рассмотрим примеры:
<!--1-й пример -->
...
<fecomponenttransfer>
<feFuncR type="linear" slope="5" intercept="-0.5" />
<feFuncG type="linear" slope="0.2" />
<feFuncB type="linear" slope="0.2" />
<feFuncA type="identity" />
</fecomponenttransfer>
...
Здесь feFuncR
, feFuncG
, feFuncB
, feFuncA
— красный, зеленый, синий и канал прозрачности соответственно. type
— тип преобразования, slope
— множитель, intercept
— добавляемое (отнимаемое) значение. T.е. <feFuncR type="linear" slope="5" intercept="-0.5" />
значит: red = red * 5 - 0.5
Вот так, например, можно сделать изображение полупрозрачным:
<!--2-й пример -->
...
<fecomponenttransfer>
<fefunca type="linear" slope="0.5" />
</fecomponenttransfer>
...
A вот так выделить только синий канал:
<!--3-й пример -->
...
<fecomponenttransfer>
<fefuncr type="linear" slope="0" />
<fefuncg type="linear" slope="0" />
<fefuncb type="linear" slope="1" />
</fecomponenttransfer>
...
Или просто заполнить значения атрибутов случайными значениями и получить интересный эффект.
<!--4-й пример -->
...
<fecomponenttransfer>
<fefuncr type="linear" slope="10" intercept="-4" />
<fefuncg type="linear" slope="1.5" intercept="1" />
<fefuncb type="linear" slope="2" intercept="-1" />
</fecomponenttransfer>
...
Вот демо всех примеров, приведенных выше.
Фильтр <fecomponenttransfer>
поддерживает не только линейные преобразования. Тип преобразований задается атрибутом type
и может принимать значения identity | table | discrete | linear | gamma
. Давайте бегло взглянем, что из себя представляет каждый из типов.
fecomponenttransfer с type="table"
В случае fecomponenttransfer
с типом table
функция преобразования для канала будет определена путем линейной интерполяции между значениями, указанными в атрибуте tablevalues
. А вот так, например, можно добиться эффекта «негатива», используя табличные значения:
...
<fecomponenttransfer>
<fefuncr type="table" tablevalues="1 0" />
<fefuncg type="table" tablevalues="1 0" />
<fefuncb type="table" tablevalues="1 0" />
</fecomponenttransfer>
...
fecomponenttransfer с type="discrete"
Для типа discrete
функция будет ступенчатой, в соответствии со значениями, указанными в атрибуте tablevalues
. Вот несколько примеров:
<!-- 1-й пример -->
...
<fecomponenttransfer>
<fefuncr type="discrete" tablevalues="1 0" />
<fefuncg type="discrete" tablevalues="0 0" />
<fefuncb type="discrete" tablevalues="0 0" />
</fecomponenttransfer>
...
<!--2-й пример -->
...
<fecomponenttransfer>
<fefuncr type="discrete" tablevalues="1 0" />
<fefuncg type="discrete" tablevalues="0 0" />
<fefuncb type="discrete" tablevalues="0 0" />
</fecomponenttransfer>
...
<!-- 3-й пример -->
...
<fecomponenttransfer>
<fefuncr type="discrete" tablevalues="1 1 1" />
<fefuncg type="discrete" tablevalues="0 0.8 1" />
<fefuncb type="discrete" tablevalues="0 0.5 1" />
</fecomponenttransfer>
...
<!-- 4-й пример -->
...
<fecomponenttransfer>
<fefuncr type="discrete" tablevalues="0 0" />
<fefuncg type="discrete" tablevalues="0.1 0.6" />
<fefuncb type="discrete" tablevalues="0.3 0.9" />
</fecomponenttransfer>
...
Имеется также возможность задавать значения гаммы каждого канала при помощи типа фильтра type="gamma"
и атрибутов amplitude
, exponent
и offset
для каждого из каналов.
Например, <fefuncg type="gamma" amplitude="1.2" exponent="0.5" offset="0.2" />
значит: green = 1.2 * pow(green, 0.5) + 0.2
Демо:
<!-- 1-й пример -->
...
<fecomponenttransfer>
<fefuncr type="gamma" amplitude="1.1" exponent="1" offset="0" />
<fefuncg type="gamma" amplitude="1.1" exponent="1" offset="0" />
<fefuncB type="gamma" amplitude="1.3" exponent="0.9" offset="0.5" />
</fecomponenttransfer>
...
<!-- 2-й пример -->
...
<fecomponenttransfer>
<fefuncr type="gamma" amplitude="2" exponent="1" offset="0.1" />
<fefuncg type="gamma" amplitude="1" exponent="1.2" offset="0.1" />
<fefuncB type="gamma" amplitude="1.4" exponent="1" offset="0.1" />
</fecomponenttransfer>
...
<!-- 3-й пример -->
...
<fecomponenttransfer>
<fefuncr type="gamma" amplitude="0.1" exponent="1" offset="0.1" />
<fefuncg type="gamma" amplitude="1" exponent="3" offset="0.1" />
<fefuncB type="gamma" amplitude="0.1" exponent="1" offset="0.1" />
</fecomponenttransfer>
...
<!-- 4-й пример -->
...
<fecomponenttransfer>
<fefuncr type="gamma" amplitude="0.4" exponent="1" offset="0.4" />
<fefuncg type="gamma" amplitude="1" exponent="0.33" offset="0.33" />
<fefuncB type="gamma" amplitude="0.1" exponent="1" offset="0.1" />
</fecomponenttransfer>
...
feColorMatrix
Фильтр позволяет умножить каждый пиксель исходного изображения в виде вектора, образованного каналами R
, G
, B
, A
и дополненного до размерности 5, на матрицу 5×5. В результате мы получим вектор, представляющий из себя каналы R'
, G'
, B'
, A'
каждого пикселя результирующего изображения.
| R' | | a00 a01 a02 a03 a04 | | R |
| G' | | a10 a11 a12 a13 a14 | | G |
| B' | = | a20 a21 a22 a23 a24 | * | B |
| A' | | a30 a31 a32 a33 a34 | | A |
| 1 | | 0 0 0 0 1 | | 1 |
Давайте сразу перейдем к примеру. Знакомый всем эффект «сепия» можно получить с помощью вот такой матрицы:
0.343 0.669 0.119 0 0
0.249 0.626 0.130 0 0
0.172 0.334 0.111 0 0
0 0 0 1 0
0 0 0 0 1
Матрица записывается в атрибут values
фильтра <fecolormatrix>
с типом matrix
в виде значений, разделенных пробелом.
Последнюю строку не нужно указывать, т.к. она всегда равна | 0 0 0 0 1 |
.
<fecolormatrix type="matrix" values="0.343 0.669 0.119 0 0 0.249 0.626 0.130 0 0 0.172 0.334 0.111 0 0 0 0 0 1 0" />
Для удобства чтения матрицу можно записать в таком виде:
<!-- 1-й пример -->
...
<fecolormatrix type="matrix"
values="0.343 0.669 0.119 0 0
0.249 0.626 0.130 0 0
0.172 0.334 0.111 0 0
0 0 0 1 0" />
...
Давайте посмотрим еще на несколько примеров с различными матрицами:
<!-- 2-й пример -->
...
<fecolormatrix type="matrix"
values="0.788 -0.262 0.474 0 0
0.1 1.032 -0.132 -0.1 0
-1 2.1 0.912 -2.8 0
0 0 0 1 0" />
...
<!-- 3-й пример -->
...
<fecolormatrix in="SourceGraphic" type="matrix"
values="5 0 0 0 -0.2
0 1.2 0 0 -0.2
0 5 1.2 0 -0.2
5 0 0 1 0 "/>
...
<!-- 4-й пример -->
...
<fecolormatrix type="matrix"
values="1.2 0 0 0 -0.2
2 0 2 2 -0.2
2 2 1.2 0 -0.2
2 0 0 1 0"/>
...
Вот результат:
Частные случаи цветовых матриц — это поворот изображения по цветовому кругу, изменение цветности и т.п. Чтобы упростить жизнь разработчикам и не требовать умножения на матрицы для типовых операций в спецификации для фильтров type=saturate
, type=hueRotate
, type=luminanceToAlpha
. Давайте рассмотрим примеры их использования:
Обесцвечивание с type="saturate"
, а также примеры, где цветность увеличена в 0, 0.5, 2, 5 раз, используя type="saturate"
:
<fecolormatrix type="saturate" values="0" /> <!-- 1-й пример -->
...
<fecolormatrix type="saturate" values="0.5" /> <!-- 2-й пример -->
...
<fecolormatrix type="saturate" values="2" /> <!-- 3-й пример -->
...
<fecolormatrix type="saturate" values="5" /> <!-- 4-й пример -->
Поворот по цветовому кругу на 40, 120, 240, 320 градусов, используя type="hueRotate"
:
<fecolormatrix type="hueRotate" values="40" /> <!-- 1-й пример -->
...
<fecolormatrix type="hueRotate" values="120" /> <!-- 2-й пример -->
...
<fecolormatrix type="hueRotate" values="240" /> <!-- 3-й пример -->
...
<fecolormatrix type="hueRotate" values="360" /> <!-- 4-й пример -->
Свертка feConvolveMatrix
В процессе свертки матрица коэффициентов «умножается» на значения каналов пикселей изображения. Будет намного проще представить это графически:
Действие над изображением (или фильтрование изображения) определяется матрицей свертки m
. Матрица свертки определяет то, как конкретный пиксель зависит от соседних пикселей в процессе свертки. Пиксель у
в результирующем изображении зависит от пикселей x0 … x8 исходя из следующей формулы:
y = x0×m0 + x1×m1 + ... + x8×m8
Свертка используется в цифровой обработке изображений для различных целей. Это размытие, искусственное увеличение резкости и другие интересные эффекты.
Давайте посмотрим, как можно немного «подтянуть» резкость классического нечеткого #duckface изображения при помощи вот такого фильтра свертки с размерностью 3:
...
<feConvolveMatrix
order="3"
kernelMatrix=" 1 -1 1
-1 -1 -1
1 -1 1">
</feConvolveMatrix>
...
Оригинальное изображение (слева) и результат фильтрации (справа)
Далее представлены еще несколько примеров для различных фильтров свертки:
<!-- 1-й пример -->
...
<feConvolveMatrix order="3" kernelMatrix="1 -1 1 -1 -0.1 -1 1 -1 1"></feConvolveMatrix>
...
<!-- 2-й пример -->
...
<feConvolveMatrix order="3" kernelMatrix="9 0 0 0 1 0 0 0 -9"></feConvolveMatrix>
...
<!-- 3-й пример -->
...
<feConvolveMatrix order="3" kernelMatrix="-1 -1 -1 -1 7 -1 -1 -1 -1"></feConvolveMatrix>
...
<!-- 4-й пример -->
...
<feConvolveMatrix order="5" kernelMatrix="1 1 1 1 1 1 -2 -2 -2 1 1 -2 .01 -2 1 1 -2 -2 -2 1 1 1 1 1 1"></feConvolveMatrix>
...
Композитные операции c feComposite
При помощи feComposite
можно осуществлять арифметические и логические операции над слоями в svg.
<feComposite
in="source1"
in2="source2"
operator="xor"/>
Давайте рассмотрим возможные значения на примерах:
Режимы смешивания слоев с feBlend
При помощи feBlend
можно осуществлять смешивание слоев в svg.
<feBlend
in="source1"
in2="source2"
mode="lighten"/>
Давайте рассмотрим возможные значения на примерах. Их не так много, как в photoshop и подобных редакторах, но все же есть наиболее часто используемые:
Текстура (повторяющееся изображение) с feTile
feTile
позволяет сделать в svg текстуру. Это очень похоже на background-repeat: repeat;
в html
<feTile in="source" />
Демо c svg-фильтрами:
В качестве демо посмотрите, что мы делали на halloween
Еще несколько примеров будут опубликованы в ближайшее время отдельными статьями.
В заключение:
Это первая статья с основами SVG фильтров. Продолжение седует…
Подписывайтесь на наши группы в Ваших любимых соц. сетях.
Полезнейшая статья, спасибо автору за работу!
Не нашел на сайте подписки на rss. Где-то есть?
http://html5.by/feed/
Если вдруг на каком-нибудь сайте не будет «заветной кнопки», пробуйте «sitename/rss» или «sitename/feed»
404
спасибо, поправил ;)
Дайте, пожалуйста, свой контакт какой-нибудь. У меня есть вопрос, может вы сможете помочь мне.
Или напишите мне сюда: https://vk.com/vyacheslav_petroff
Добрый вечер! Я автор этого вопроса.
Как быть, если очень хочется сохранить изображение отфильтрованное с помощью svg filter? И чтобы было яснее для чего это мне нужно, отмечу что я хочу использовать это в js приложении собранным с использованием Phonegap. Одно из составляющих приложения, это как раз съемка фотографий и применение к ним фильтров, аля мини инстаграм.
Привет! Вы можете использовать консольный браузер на сервере (например PhantomJS)
Те процесс примерно такой:
Скажите понятно ли я рассказал :) ?
Я понял. Спасибо большое) Обязательно попробую.
Здравствуйте, подскажите пожалуйста визуальный редактор в котором можно «поиграться» с фильтрами
годнейший материал, спасибо!
Офигенная статья, автору уважуха. Очень полезная статья, рад, что такую нашёл! СПАСИБО!