Эффекты фильтров SVG. Часть 2. Контурный текст при помощи feMorphology

Автор оригинала: Sara Soueidan
  • Перевод

Предлагаемая серия статей "Эффекты фильтрации SVG" Sara Soueidan, внештатного разработчика UI/UX интерфейса и автора многих технических статей, проживающей в Ливане, посвящена работе фильтров SVG и состоит из следующих статей:


Эффекты фильтрации SVG


  1. Эффекты фильтрации SVG. Часть 1. SVG фильтры 101.
  2. Эффекты фильтрации SVG. Часть 2. контурный текст при помощи feMorphology
  3. Эффекты фильтрации SVG. Часть 3. Эффект постеризации изображения при помощи feComponentTransfer.
  4. Эффекты фильтрации SVG. Часть 4. Двухцветные изображения при помощи feComponentTransfer.
  5. Эффекты фильтрации SVG. Часть 5. Соответствие текста текстуре поверхности при помощи feDisplacementMap



Во второй части серии об SVG-фильтрах Sara Soueidan знакомит нас с фильтром feMorphology и приводит несколько примеров его использования для создания интересных эффектов.



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


< feMorphology> — одна из моих любимых операций SVG-фильтра. Это также одна из самых простых операций, и результаты ее применения к различным элементам всегда предсказуемы.


Что такое морфинг?


Морфинг означает преобразование или изменение формы или вида объекта.


Морфологический фильтр оперирует формой объекта. Он обеспечивает два предопределенных преобразования формы: эрозия (т.е. прореживание или сокращение) и расширение (т.е. А. утолщение или расширение). Иными словами, примитив feMorphology можно использовать для сжимания или расширения элемента.


Технически говоря, обе эти операции работают на уровне пикселя, расширяя пиксель на соседние пиксели (dilate), или разрушая соседние пиксели по краям пикселя, которым управляют (erode), сохраняя при этом контур на границе этого пикселя. Величина, на которую расширяется пиксель, или количество соседних пикселей, используемых для “растяжки” или “расширения” пикселя, определяется параметром radius.


<feMorphology 
    in=".." result=".." 
    operator="dilate || erode" radius="">
</feMorphology>

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


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


Чтобы использовать фильтр, нам не нужно вдаваться в занудные мелочи того, что морфинг делает на пиксельном уровне. Достаточно знать, что вы можете предоставить одно или два значения радиуса в feMorphology, которые будут определять величину, на которую элемент будет сжиматься или расширяться. Если в атрибуте radius указать два числа, то первое будет соответствовать x-радиусу, а второе y-радиусу.


Морфинг Изображений


Если операцию feMorphology применить к изображениям, то последуют два, как правило, предсказуемых, результата:


  • Размер изображения уменьшается, если используется оператор erode, или возрастает, если используется оператор dilate.
  • При любым операторе изображение выглядит так, как будто оно было нарисовано большой малярной кистью, с небольшим количеством мелких деталей.

Таким образом, чтобы применить эффект морфинга к изображению, наш код должен выглядеть примерно так:


<svg width="450" height="300" viewBox="0 0 450 300">
    <filter id="erode">
        <feMorphology operator="erode" radius="3"></feMorphology>
    </filter>
    <image xlink:href="..." width="90%" height="90%" x="10" y="10" filter="url(#erode)"></image>
</svg>

В этом фрагменте мы размываем (сжимаем) изображение (в пикселях) на 3 пикселя. На следующем рисунке показан результат этого кода. Обратите внимание, что размер изображения справа немного меньше:


Справа результат применения эффекта размывания морфинга к изображению слева
Рис_2. Справа результат применения эффекта размывания морфинга к изображению слева.


Теперь, если мы сохраним тот же радиус морфинга и изменим оператор с erode на dilate, эффект будет аналогичным, но также отчетливо различаться:



Рис_3. Справа результат применения операции dilate morph к изображению слева.


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


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


  • erode (это значение используется по умолчанию) устанавливает для каждого пикселя наименьшую яркость или наибольшую непрозрачность его сообщества, соответственно для каждого из каналов R, G, B и A;
  • dilate устанавливает для каждого канала каждого пикселя значения, соответствующие самому яркому или наименее прозрачному значению своего сообщества.

Если отбросить технические подробности в сторону, то применение feMorphology к изображениям почти всегда будет иметь один и тот же результат: сжатие или растяжение мелких деталей изображения как копия изображения с темным или светлым основными контуром.



Однако применение feMorphology к одноцветным элементам, таким как текст, только сжимает или растягивает его, не производя никаких заметных изменений цвета пикселей, потому что у нас все равно есть только один цвет для работы…


Добавление цветного контура к тексту с помощью feMorphology


Сейчас мы можем добавить контур к тексту в SVG, используя для этого текста атрибут stroke.


<!-- Adding an outline to SVG text using strokes -->
<text font-size="80px" dx="100" dy="200" font-weight="700" stroke="deepPink" stroke-width="3px">Stroked Text</text>

Добавление контура, который обычно центруется по краям текста так, что половина его толщины перекрывается самим текстом, делает текст тоньше, даже если это и не предполагалось. Вместо этого мы можем расширить (dilate) текст на толщину контура или обводки при помощи feMorphology.


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


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


Сравнение исходного текста с текстом, имеющим обводку, и контуром, созданным при помощи **feMorphology**
Рис_4. Сравнение исходного текста с текстом, имеющим обводку, и контуром, созданным при помощи feMorphology.


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


Итак, давайте по шагам создадим цветной фрагмент текста с контуром. Вот результат, к которому мы будем стремиться:


Конечный результат
Рис_5. Конечный результат.


Итак, мы создадим SVG, содержащее наш текст и фильтр, запускающий простую операцию расширения. Размер расширения текста зависит от толщины контура, который мы хотим получить.


<svg width="900" height="200" viewBox="100 0 900 200">
    <filter id="outline">
        <feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="4"></feMorphology>
    </filter>

    <!-- DILATED TEXT -->
    <text font-size="85px" dx="125" dy="130" font-weight="700" filter="url(#outline)">upgrade yourself</text>
</svg>

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


Текст после утолщения
Рис_6. Текст после утолщения.


… по сравнению с исходным текстом, который имеет темно-синий цвет заливки:


Исходный текст
Рис_7. Исходный текст.


Чтобы создать эффект контура, мы наложим исходный текст поверх расширенного, что оставит видимыми только края расширенного текста (наши дополнительные 4px) вокруг исходного текста, делая их похожими на контур. Наложение текста поверх его контура (расширенного текста) будет выполнено при помощи feMerge. Как это делается мы рассмотрели в предыдущей статье.


Что еще нам нужно сделать, прежде чем расположить контур вокруг текста, так это окрасить сам контур. Подобно тому, как мы это делали в предыдущей статье, зальем область фильтра нужным цветом, а затем сложим цветовой слой с уже расширенным текстовым слоем, т.е. нашим контуром, с помощью оператора in. В результате будут отображаться только те части цветной заливки, которые пересекаются с расширенным текстом, таким образом раскрашивая его. Затем, мы соединим получившийся цветной контур с исходным текстом, чтобы получить желаемый результат.


Теперь наш код выглядит так:


<svg width="900" height="200" viewBox="100 0 900 200">
<filter id="outline">
    <feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="4"></feMorphology>

    <feFlood flood-color="#32DFEC" flood-opacity="1" result="PINK"></feFlood>
    <feComposite in="PINK" in2="DILATED" operator="in" result="OUTLINE"></feComposite>

    <feMerge>
        <feMergeNode in="OUTLINE" />
        <feMergeNode in="SourceGraphic" />
    </feMerge>
</filter>

<!-- DILATED TEXT -->
<text font-size="85px" dx="125" dy="130" font-weight="700" filter="url(#outline)">upgrade yourself</text>
</svg>

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


А вот демо приведенного выше кода:



Цвет заливки текста можно указать либо в вашем CSS, либо в элементе text при помощи атрибута fill. Цвет контура можно настроить в атрибуте flood-color примитива feFlood.


Отлично! А если вы захотите изменить цвет контура? Вам придется снова использовать примитив feFlood и комбинировать цветную заливку с контуром. И каждый раз, когда вы захотите изменить цвет контура, вам придется делать то же самое снова и снова. Это, надо признать, слишком утомительно. К счастью, есть более простой способ.


Выбивание текста


Кроме добавления контура к тексту мы можем создать также контурный, т.е. выбитый текст, что означает, что внутренняя часть текста будет “вырезана”, чтобы вы могли видеть фон позади него через контур. Пример такого эффекта может выглядеть как текст на следующем GIF, который показывает изменение цвета фона, и как этот фон можно увидеть внутри нашего текста. Вот демо, которое мы будем создавать в этом разделе:


Пример выбитого текста
Рис_8. Пример выбитого текста.


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


Если вместо захвата и расширения Альфа-канала текста (который по умолчанию черный) вы захватываете сам исходный текст (который может иметь любой цвет заливки!), расширите его, а затем снова используйте текст, чтобы вырезать внутреннюю часть расширенного текста, то получите контур, который выходит из самого исходного текста. Это означает, что цвет этого контура всегда будет совпадать с цветом исходного текста. А так как мы можем определить цвет заливки исходного текста в CSS, это означает, что у вас есть контур текста, который отделен от его стилей. (Ура разделение забот!) Затем вы можете применить этот фильтр к любому фрагменту текста и изменить цвет этого текста в CSS в любое время, без необходимости настройки кода фильтра. Наш улучшенный код теперь выглядит так:


<svg width="900" height="450" viewBox="0 0 900 450">
    <filter id="outliner">

        <!-- Start by grabbing the alpha channel of the text and dilating it-->
        <feMorphology operator="dilate" radius="8" in="SourceAlpha" result="THICKNESS" />

         <!-- Next, grab the original text (SourceGraphic) and use it to cut out the inside of the dilated text -->
        <feComposite operator="out" in="THICKNESS" in2="SourceGraphic"></feComposite>
    </filter>

    <text dx="100" dy="300" filter="url(#outliner)" letter-spacing="10px">SVG Rocks</text>
</svg>

Используя хороший шрифт, наше демо теперь выглядит так:



Рис_9. Результат нашей работы.


В своей таблице стилей мы можем выбрать цвет контура, а также цвет фона SVG. Вы также можете выбрать изображение за текстом внутри SVG. В коде ниже я абсолютно без причины использую анимацию CSS, чтобы изменять цвет фона, кроме того, что это красиво.


svg text {
    font-family: 'Bangers', cursive;
    font-size: 150px;
    letter-spacing: 13px;
    fill: #000; /* This fill color determines the color of the outline */
}

svg {
    background-color: gold;
    animation: colorsssss 2s linear infinite;
    animation-delay: 3s;
}

@keyframes colorsssss {
    50% {
        background-color: deepPink;
    }
}

Выше SVG фильтр является многоразовым через SVG так же как HTML. Если вы хотите применить его к HTML-элементу, вы можете сделать это с помощью свойства filter; просто поместите фильтр в HTML и “вызовите” его в CSS:


h2 {
    filter: url(#outliner);

    /* You can change the color of the outline here by changing the color of the heading */
    color: deepPink;
}

И наша готовая демо, которая включает в себя HTML-заголовок с примененным к нему фильтром:



Моя любимая вещь об этом рецепте фильтра заключается в том, что его можно использовать в качестве визуального улучшения. Если браузер не поддерживает SVG-фильтры, или он не поддерживает CSS-фильтры, или он не поддерживает применение фильтров SVG в HTML-элементы, пользователь получит исходный текст без контуров и эффекта просвечивания, примененных к нему. О, а вишенка на торте сверху? И SVG, и HTML-текст будут полностью доступны для поиска и изменения. Ура прогрессивному улучшению! Да здравствует SVG!


Заключение


Используя всего две операции фильтрации в SVG, вы можете применить эффект выделенного текста к текстовому содержимому SVG или HTML. Поместите этот фильтр в HTML и используйте его, когда вам нужно.


В следующей статье этой серии мы рассмотрим feComponentTransfer, один из моих любимых примитивов фильтра, и посмотрим, как он работает и какие эффекты мы можем создать с его помощью. Оставайтесь с нами.

  • +18
  • 3,3k
  • 4
Поделиться публикацией

Комментарии 4

    0
    Признаться честно гораздо легче text-stroke делать через text-shadow. В любом препроцессоре простейший миксин пишется в два счёта.
    Вот для PostCSS ismamz.github.io/postcss-utilities/docs#text-stroke
      0
      На чистом CSS не получится сделать прозрачный текст с обводкой. Единственный вариант — через нестандартный text-stroke, но он в том же IE не работает.
        0
        Скажем так. Если фон это сплошная заливка 1 цветом, то проблем нет. Если фон картинка, то уже другое дело.
        Я не против SVG и сам активно его использую, но когда части текста просто нужно text-stroke я не склонен его вгонять в SVG, а просто навешу класс и всё.
      0
      А есть инструмент который позволяет сохранить результат применения фильтров в SVG без фильтров?

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое