В третьей части серии вы узнаете, как работает feComponentTransfer и как можно постеризовать изображения при помощи этого мощного примитива SVG-фильтра.
Предлагаемая серия статей "Эффекты фильтрации SVG" Sara Soueidan, внештатного разработчика UI/UX интерфейса и автора многих технических статей, проживающей в Ливане, посвящена работе фильтров SVG и состоит из следующих статей:
Эффекты фильтрации SVG
- Эффекты фильтрации SVG. Часть 1. SVG фильтры 101
- Эффекты фильтрации SVG. Часть 2. Контурный текст при помощи feMorphology
- Эффекты фильтрации SVG. Часть 3. Эффект постеризации изображения при помощи feComponentTransfer
- SVG Filter Effects: Duotone Images with feComponentTransfer.
- SVG Filter Effects: Conforming Text to Surface Texture with feDisplacementMap
В этой статье предполагается, что вы уже знакомы с основами SVG-фильтров или прочитали первую статью этой серии — "SVG Filters 101". Если вы этого не сделали, пожалуйста, не стесняйтесь потратить несколько минут, чтобы восполнить багаж знаний.
feComponentTransfer один из самых мощных примитивов фильтра SVG. Он дает нам контроль над отдельными каналами RGBA нашего источника графики, позволяя создавать в SVG эффекты, подобные Photoshop. В этой статье, которая является первой частью статьи, посвященной feComponentTransfer, мы познакомимся с этим примитивом и посмотрим, как его можно использовать для постеризации изображений.
Постеризация или огрубление изображения подразумевает преобразование непрерывного перехода цвета на несколько диапазонов меньшего числа цветов, с резкими переходами от одного цвета к другому. Первоначально это делалось при помощи фотографических процессов для создания плакатов. — Википедия.
Постеризация происходит по всему изображению, но наиболее очевидна в районе тонкого изменения цвета.
Рис_1. Пример фотографии в формате JPEG (24-битный цвет или 16,7 млн цветов) до постеризации, контрастирующей с результатом ее сохранения в формате GIF (256 цветов). (Источник: Википедия)
В этой статье мы будем использовать feComponentTransfer, чтобы уменьшить количество цветов в изображении, что, в свою очередь, приведет к созданию приятного эффекта плаката, похожего на те, что мы видим в коммерческих или графических разработках плакатов.
Рис_2. Применение эффекта постеризации к изображению слева при помощи feComponentTransfer уменьшает количество цветов в этом изображении (справа).
Но сначала рассмотрим технические азы…
Краткий обзор feComponentTransfer
Примитив feComponentTransfer позволяет изменять каждый из R, G, B и A компонентов, присутствующих в пикселе. Другими словами, feComponentTransfer позволяет независимо манипулировать каждым каналом цвета так же, как и альфа-каналом на входе графики. Он позволяет точно управлять регулировкой яркости, регулировкой контраста, цветовым балансом или установкой порога.
Компоненты RGBA изменяются путем выполнения функций передачи этих компонентов. Для этого у каждого компонента имеется собственный элемент, называемый элементом передаточной функции (Transfer Function Element). На протяжении всей статьи я буду называть эти элементы как “компонентные элементы” — т.е. элементы, которые относятся к отдельным компонентам RGBA. Эти элементы вложены в feComponentTransfer. Так feComponentTransfer не делает ничего кроме размещения индивидуальных RGB компонентных элементов. Компонентные элементы RGBA это: feFuncR, feFuncG, feFuncB и feFuncA.
Атрибут type используется в компонентном элементе для определения типа функции, которую вы хотите использовать для изменения этого компонента. В настоящее время существует пять типов функций: identity, table, discrete, linear и gamma. Эти типы функций используются для изменения компонентов R/G/B/A источника графики. Мы рассмотрим в этой серии большинство из них и увидим, как их можно использовать.
<feComponentTransfer>
<!-- The RED component -->
<feFuncR type="identity | table | discrete | linear | gamma"></feFuncR>
<!-- The GREEN component -->
<feFuncG type="identity | table | discrete | linear | gamma"></feFuncG>
<!-- The BLUE component -->
<feFuncB type="identity | table | discrete | linear | gamma"></feFuncB>
<!-- The ALPHA component -->
<feFuncA type="identity | table | discrete | linear | gamma"></feFuncA>
</feComponentTransfer>">
Для каждого типа функции существует один или несколько атрибутов, позволяющих указать дополнительные сведения об используемой функции. Например, функция linear имеет атрибут slope, который используется для указания наклона линейной функции, которая будет использоваться для изменения компонента, к которому она применена.
Одновременно можно изменить один или несколько компонентов. Это означает, что feComponentTransfer может содержать один, два, три или все компонентные элементы одновременно. Можно также изменять каналы независимо друг от друга, применяя разные функции к каждому компонентному элементу.
Возможность использовать различные функции на разных компонентных элементах означает, что у вас имеется очень большой контроль над цветами источника графики на самом низком уровне пикселей. Например, вы можете изменить красный и синий каналы, сопоставив им два новых цвета, и оставить зеленый неизменным или только увеличить его интенсивность. Это низкоуровневое управление компонентами означает, что вы сможете применять функции, подобные Photoshop, к изображениям в браузере, используя несколько строк кода. Я не знаю как вы, но (начинающий) дизайнер во мне думает, что это супер интересно!
Пример: использование Альфа-компоненты для уменьшения непрозрачности объекта
Простой пример из реальной жизни — использование компонентного элемента feFuncA для уменьшения непрозрачности источника графики. В первой статье этой серии мы увидели, как можно использовать feColorMatrix для уменьшения непрозрачности элемента путем изменения значения Альфа-канала в цветовой матрице. Я лично предпочитаю использовать feComponentTransfer для этой своеобразной работы.
Применение к источнику следующего фильтра уменьшает непрозрачность этого источника до 0,5:
<filter id="redOp">
<feComponentTransfer>
<feFuncA type="table" tableValues="0 0.5"></feFuncA>
</feComponentTransfer>
</filter>
Мы упомянули выше, что у нас есть пять различных функций, которые мы можем использовать для управления компонентами RGBA. Тип функции table работает путем сопоставления значений компонента, который является альфа-каналом в нашем примере, с серией значений, предоставленных атрибутом tableValues.
Итак, что это значит?
Альфа-канал элемента обычно лежит в диапазоне [0, 1]. Используя функцию table и предоставляя два значения: 0 и 0.5, мы, по сути, говорим браузеру сопоставить альфа-диапазон [0, 1] с новым диапазоном: [0, 0.5]. При этом непрозрачность уменьшается наполовину.
Более подробный пример функции table мы рассмотрим в следующей статье. Сейчас я хочу пролить свет на тип функции discrete. Итак, давайте посмотрим, как она работает и что мы можем с ней сделать.
Эффект постеризации изображения: уменьшение количества цветов в изображении с помощью функции discrete
Функция discrete используется для уменьшения количества цветов в изображении или в компоненте, если используется только один компонент. Уменьшение количества цветов в изображении означает, что вместо плавного линейного изменения цвета вы увидите более резкие цветовые переходы, которые делают изображение похожим на полосы или кластеры цвета, что приводит к эффекту, похожему на плакат.
Рис_3. Изображение справа является копией изображения слева, к которому применили дискретную функцию для уменьшения количества цветов в нем до 5 на компонент.
На рисунке выше Вы можете увидеть, что вместо плавных переходов цвета резко изменяются, создавая цветовые полосы и кластеры, а изображение выглядит более “постеризованным”.
Лично мне функция discrete напоминает функцию синхронизации steps() в CSS. По сравнению с линейной функцией пошаговая функция переходит от одного значения к другому, а не линейно перемещается между ними.
Как и функция table, функция discrete принимает ряд значений, указанных в атрибуте tableValues. Функция discrete отличается от table тем, как она использует эти значения.
Используя tableValues, вы предоставляете браузеру конечный список значений, с которыми он должен сопоставить компонент цвета. И так как вы предоставляете конечный список значений, то получите конечное количество цветов, создавая таким образом цветовые полосы и кластеры, которые в противном случае были бы линейными переходами цветов.
Эта функция определяется шагами функции, заданными в атрибуте tableValues, который предоставляет список из n значений для идентификации функции step, состоящей из n шагов.— Спецификация SVG Filters
Посмотрим, что это означает простым языком. Предположим у нас есть следующий фрагмент кода:
<svg width="500" height="335" viewBox="0 0 500 335">
<filter id="posterize">
<feComponentTransfer>
<feFuncR type="discrete" tableValues="0 .5 1" />
</feComponentTransfer>
</filter>
<image xlink:href="..."cwidth="100%" height="100%" x="0" y="0"
filter="url(#posterize)"></image>
</svg>
В приведенном выше фрагменте кода мы применяем дискретную функцию для изменения канала красного цвета в источнике изображения. Мы предоставляем 3 разных значения, которым браузер должен сопоставить значения красного цвета. В SVG-фильтре значения компонентов представлены в виде дробей в диапазоне [0, 1]. Это означает, что значение красного компонента в любом пикселе может быть 0 (0% красный / полностью черный), 1 (100% красный) или любое значение (оттенок красного) между ними. То же самое касается зеленого, синего и альфа каналов.
Для любого числа введенных вами значений (n) браузер создаст n диапазонов. Более конкретно, он разделит [0, 1] на n диапазонов. Затем он будет отображать значения цветов, которые лежат в пределах этих диапазонов на n значений. Применим эту логику к нашему фрагменту кода:
- браузер видит три разных значения красного в tableValues;
- он делит значения красного цвета в диапазоне [0, 1] на три равных части. Так что наши три диапазона выглядят следующим образом:
- [0, 0.33]
- [0.33, 0.66]
- [0.66, 1]
- далее, браузер проверяет значение красного цвета каждого пикселя изображения и определяет, в каком диапазоне оно находится;
- затем все значения красного одного диапазона отображаются новым значением, сопоставленным этому диапазону, из тех, что вы предоставили. Отображение выглядит следующим образом:
- цвета в диапазоне [0, 0.33] отображаются как 0;
- цвета в диапазоне [0.33, 0.66] отображаются как 0.5;
- цвета в диапазоне [0.66, 1] отображаются как 1.
Вы также можете думать об этом процессе как о включении или выключении оттенков цвета. Когда вы предоставляете дискретные значения для цвета, вы говорите браузеру, что будут включены только эти значения, а если пиксель содержит значение, которое не равно одному из них, то его следует отключить и заменить одним из разрешенных. Так, например, значение цвета 0.8 считается выключенным и будет заменено на 1 (потому что это значение лежит в третьем диапазоне).
Ниже приводится нарисованная вручную иллюстрация этого цветового отображения, которую я нарисовала, когда рассуждала об этом. Возможно, Вам она пригодится.
Рис_4. Отображение значений цвета в цвет диапазона.
К тому времени, когда браузер пройдет по всем пикселям изображения, вы замените большое количество значений красного на небольшое число, которое вы выбрали в tableValues, таким образом, заменяя плавные изменения цвета резкими переходами, а изображение выглядит так, как будто оно сделано из кластеров или полос цвета.
Ниже приводится демо применения приведенного выше фрагмента кода к изображению с большим количеством красного цвета. Ограничивая число красных в пикселях изображения и обнуляя красные в некоторых из них, изображение проявляет общее заметное уменьшение красного цвета, особенно в нижней части изображения:
Изменение числа дискретных значений и/или изменение самих значений будет изменять общий результат. Вы, возможно, не захотите придавать значению цвета 0, чтобы избавиться от некоторых черных областей изображения. Например, на изображении неба выше, наверно, не должно быть никаких кластеров или полос черного цвета в версии постеризации изображения, потому что это все еще изображение неба. Для этого нужно иметь больше, чем два или три цвета, иначе изображение потеряет большую часть своей изобразительности.
Чтобы создать такой эффект, я ограничила количество RGB-цветов пятью, начиная с наименьшего значения 0.25:
<filter id="posterize">
<feComponentTransfer>
<feFuncR type="discrete" tableValues=".25 .4 .5 .75 1" />
<feFuncG type="discrete" tableValues=".25 .4 .5 .75 1" />
<feFuncB type="discrete" tableValues=".25 .4 .5 .75 1" />
</feComponentTransfer>
</filter>
Вы можете поиграть с эффектом в следующем демо:
Заключение
Я надеюсь, что эта статья помогла немного прояснить feComponentTransfer и показала вам, насколько мощным может быть контроль цвета на уровне пикселей и компонентов.
В следующей статье мы рассмотрим еще два мощных типа передаточной функции feComponentTransfer. Мы рассмотрим, как можно имитировать эффект двутонального изображения Photoshop, и как можно контролировать яркость, контрастность и интенсивность цветов изображения с помощью feComponentTransfer. Оставайтесь с нами.