详解feColorMatrix
你见过去年年底Spotify分享的一个主题吗?他们通过图像颜色处理,达到一个令人折服的视觉审美效果。
图像处理是一种非常强大的处理机制,在项目中添加一点小技巧,Web浏览器通过Web的过滤器可以动态处理图像色彩,这样将使你的项目能脱颖而出。
CSS vs. SVG
今年早些时候,推出的CSSgram库,使用CSS的filter
和Blend Modes重新创建了Instagram过滤器。
现在使用CSS Blend Modes可以做一些修补,但是CSS的filter
有一个极大的缺陷,其缺乏一个关键特性来对每个通道做处理。虽然CSS的filter
很方便(其实就是源自于SVG的一种快捷方式),但无法提供控制RGBA通道。SVG(特别是feColorMatrix
)提供了更强大的力量,直接让CSS的filter
升了一个层级,能更好的处理图像和得到更多的特殊效果。
SVG filters
在SVG的世界中,filter效果使用fe-
前缀表示(就是“过滤效果”)。他们可以产生各种各样的色彩效果,也可以产生模糊和3D纹理。虽然fe-
前缀一词有点松,但这篇文章后面做的总结都是有关于SVG的filter效果的方法。
目前浏览器对SVG filter的支持情况如下所示:
是的,在大多数情况之下,SVG filter都得到较好的支持,除非你还需要兼容IE9或IE9以下的浏览器。相对于CSS的filter和Blend Modes而言,SVG filter的浏览器支持度还是相对稳定的。不过也有一些奇怪的问题,并不像CSS的Blend Modes只在Chrome v46才会有multiply
、difference
和exclusion
问题。
**注意:**一些3D过滤效果,比如feConvolveMatrix
,在某些浏览器中有已知的缺陷。尽管本文主要关注是feColorMatrix
,但也无法做到。同时记住,在任何浏览器中性能将不可避免地遭到微小的影响。
filters的使用
SVG filters的使用基本上类似这样:
<svg>
<filter id="filterName">
// filter definition here can include
// multiple of the above items
</filter>
</svg>
在SVG中,你可以声明一个filter。在大多数情况之下,可以使用SVG的defs
来声明你想要的filter,然后可以在CSS这样使用声明的filter:
.filter-me {
filter: url('#filterName');
}
filter的URL
是相对的,所以filter: url('../img/filter.svg#filterName')
和filter: url('http://una.im/filters.svg#filterName')
都是有效的。
feColorMatrix
当谈到颜色的处理,feColorMatrix
是你最好的选择。feColorMatrix
是过滤中的一种类型,使用矩阵来影响颜色的每个通道(基于RGBA),你可以将其想象成Photoshop中通道编辑一样。
feColorMatrix
看起来像这样(原始图像RGBA的值默认为1
)。
<filter id="linear">
<feColorMatrix
type="matrix"
values="R 0 0 0 0
0 G 0 0 0
0 0 B 0 0
0 0 0 A 0 "/>
</feColorMatrix>
</filter>
矩阵计算RGBA自已每行的最终值,每个RGBA通道有自身的RGBA通道。最后一个值是一个乘数。最后RGBA的值从上向下读,像下面这个列表:
/* R G B A 1 */
1 0 0 0 0 // R = 1*R + 0*G + 0*B + 0*A + 0
0 1 0 0 0 // G = 0*R + 1*G + 0*B + 0*A + 0
0 0 1 0 0 // B = 0*R + 0*G + 1*B + 0*A + 0
0 0 0 1 0 // A = 0*R + 0*G + 0*B + 1*A + 0
下图更形象:
RGB值
着色
你可以遗漏或混合颜色通道给图像着色,像下面这样:
<!-- lacking the B & G channels (only R at 1) -->
<filter id="red">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0 "/>
</filter>
<!-- lacking the R & G channels (only B at 1) -->
<filter id="blue">
<feColorMatrix
type="matrix"
values="0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 1 0 "/>
</filter>
<!-- lacking the R & B channels (only G at 1) -->
<filter id="green">
<feColorMatrix
type="matrix"
values="0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0 "/>
</filter>
这就是将green
过滤器添加到图像上,其结果看起来像这样:
混合通道
你也可以通过混合RGB通道得到固定的颜色,并且给图像着色:
<!-- lacking the B channel (mix of R & G)
Red + Green = Yellow
This is saying there is no yellow channel
-->
<filter id="yellow">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0 "/>
</filter>
<!-- lacking the G channels (mix of R & B)
Red + Blue = Magenta
-->
<filter id="magenta">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 1 0 "/>
</filter>
<!-- lacking the R channel (mix of G & B)
Green + Blue = Cyan
-->
<filter id="cyan">
<feColorMatrix
type="matrix"
values="0 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0 "/>
</filter>
上面的示例,是在CMYK模式下混合颜色,删除red
通道将意味着green
和blue
依然存在。当green
和blue
混合将创建cyan
,red
和blue
混合将创建magenta
。
@Justin McDowell曾经写过一篇文章阐述HSL(hue, saturation, lightness)颜色。我们也需要记住,在SVG中亮度的值是指光度。在这里,每个通道都会保留一个亮度的级别,比如我们看到的图像,就保留了一个洋红色:
为什么在云上和亮度的地方会变成洋红色?看看下面的RGB颜色图:
当一个颜色值失踪后会使用其他两个值取而代之。比如,没有green
颜色通道就会没有white
、cyan
或yellow
。其实他们并没有消失,只不过他们的亮度值(或alpha
)尚未触及。让我们看看操作这些alpha
值会发生什么?
ALPHA值
我们可以通过alpha
(第四列)来突出阴影和亮度。第四行受alpha
通道影响,而第四列将影响每个通道的亮度值,如:
<!-- Acts like an opacity filter at .5 -->
<filter id="alpha">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 .5 0 "/>
</filter>
<!-- increases green opacity to be
on the same level as overall opacity -->
<filter id="hard-green">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 1 0 1 0
0 0 1 0 0
0 0 0 1 0 "/>
</filter>
<filter id="hard-yellow">
<feColorMatrix
type="matrix"
values="1 0 0 1 0
0 1 0 1 0
0 0 1 0 0
0 0 0 1 0 "/>
</filter>
在接下来的示例中,红色的矩阵基础上给blue
的通道添加了100%
的alpha
。我们还保留red
值,覆盖任何red
的痕迹,会变成blue
,而红色的亮度值中blue
和red
混合将成为magenta
。
<filter id="blue-shadow-magenta-highlight">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 0 0 0 0
0 0 1 1 0
0 0 0 1 0 "/>
</filter>
如果最后一个值小于0
(变成-1
),就会得到相反效果。blue
的痕迹就会变成red
。下面就是取值为-1
的效果:
<filter id="red-overlay">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 0 0 0 0
0 0 1 -1 0
0 0 0 1 0 "/>
</filter>
<filter id="identical-red-overlay">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0 "/>
</filter>
把-1
换成.5
,混合后颜色效果如下:
<filter id="blue-magenta-2">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 0 0 0 0
0 0 1 .5 0
0 0 0 1 0 "/>
</filter>
Blowing out channels
我们也可以通过第四行的个人通道影响整个alpha
通道。示例中有一个蓝色的天空,可以将蓝色的天空变成白色,如下:
<filter id="elim-blue">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 -2 1 0 "/>
</filter>
下面演示几个混合通道的示例:
<!-- No G channel, Red is at 100% on the G Channel, so the G channel looks Red (luminosity of G channel lost) -->
<filter id="no-g-red">
<feColorMatrix
type="matrix"
values="1 1 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 1 0 "/>
</filter>
<!-- No G channel, Red and Green is at 100% on the G Channel, so the G Channel looks Magenta (luminosity of G channel lost) -->
<filter id="no-g-magenta">
<feColorMatrix
type="matrix"
values="1 1 0 0 0
0 0 0 0 0
0 1 1 0 0
0 0 0 1 0 "/>
</filter>
<!-- G channel being shared by red and blue values. This is a colorized magenta effect (luminosity maintained) -->
<filter id="yes-g-colorized-magenta">
<feColorMatrix
type="matrix"
values="1 1 0 0 0
0 1 0 0 0
0 1 1 0 0
0 0 0 1 0 "/>
</filter>
Lighten 和 darken
您可以通过将RGB值每个通道的值设置成小于1
创建一个darken
效果,反之,将每个通道值设置成大于1
可以创建一个lighten
效果。下图能清晰的阐述这一切:
矩阵效果如下:
<filter id="darken">
<feColorMatrix
type="matrix"
values=".5 0 0 0 0
0 .5 0 0 0
0 0 .5 0 0
0 0 0 1 0 "/>
</filter>
<filter id="lighten">
<feColorMatrix
type="matrix"
values="1.5 0 0 0 0
0 1.5 0 0 0
0 0 1.5 0 0
0 0 0 1 0 "/>
</filter>
GRAYSCALE
你可以在一列中设置shade的像素值创建出灰度效果。运用的通道位置不一样,可以得到不同的灰度值。比如下面几个示例:
<filter id="gray-on-light">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
1 0 0 0 0
1 0 0 0 0
0 0 0 1 0 "/>
</filter>
<filter id="gray-on-mid">
<feColorMatrix
type="matrix"
values="0 1 0 0 0
0 1 0 0 0
0 1 0 0 0
0 0 0 1 0 "/>
</filter>
<filter id="gray-on-dark">
<feColorMatrix
type="matrix"
values="0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 1 0 "/>
</filter>
组合在一起
feColorMatrix
真正力量是能够混合多个通道,并且将这些概念运用到图像上产生一个新的图像效果。
<filter id="peachy">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 .5 0 0 0
0 0 0 .5 0
0 0 0 1 0 "/>
</filter>
在red
的通道上采用1
,green
通道上采用0.5
,而blue
通道不在正常的位置上,而alpha
设置为0.5
。看到的效果是深蓝色的痕迹(shadows),突出的红色和一半亮度绿色的混合的中间色调。如果red + green = blue
的话,那么red + (green / 2)
能得到更多的coral
色:
这是另一个示例:
<filter id="lime">
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 2 0 0 0
0 0 0 .5 0
0 0 0 1 0 "/>
</filter>
有这么多值得探索的值。Rachel Nabors的Dev Tools Challenger就是一个很好的示例。(**注:**需要使用Firefox浏览器打开)。
酷!科学!颜色过滤器!现在,你对这方面知识有一定的了解。你现在所需要的是需要自己的工具来创建你自己的效果。
如果你想了解更多的细节,建议你阅读Amelia Bellamy-Royds写的一篇文章,文章阐述了feColorMatrix
更多的细节。Sara Soueidan也写了一篇文章,在SVG中使用CSS的blend modes模式创建图像效果。
filter效果的参考
如查你理解了feColorMatrix
是什么,你就可以在此基础上创建一个工具来生成过滤器效果。下面提供一些fe-
相关的选项,希望对你有所帮助,并且能做进一步的探索。
feBlend
:类似于CSS blend modes,描述了图像通过混合模式进行交互feComponentTransfer
: 改变个人对RGBA通道的总称(如feFuncG
)feComposite
:一个原始的过滤器,定义像素图像交互方式feConvolveMatrix
:这个过滤器规定像素与他近邻将关闭交互(如:模糊、锐化)feDiffuseLighting
:定义了一个光源feDisplacementMap
: 使用另一个输入值(in2
)取代一个图像的像素值(in
)feFlood
: 完成过滤器的填充区域指定的颜色和alpha
等级feGaussianBlur
:输入的模糊值和标准值的偏差feImage
:使用其他的过滤器(像feBlend
或feComposite
)feMerge
: 允许异步过滤效果应用,而不是分层feMorphology
: 削弱或扩张源图像feOffset
:用来创建阴影feSpecularLighting
: 通过alpha
创建凹凸贴图,又将其称之为"镜面"(Phong Reflection Model)feTile
: 指图像如何重复填补空间feTurbulence
: 允许创建纹理
扩展阅读
- MDN Docs on feColorMatrix
- w3c Filter Docs
- Smarter SVG Filters
- feColorMatrix Overview on Web Platform
- SVG 研究之路 (11) - filter:feColorMatrix
本文根据@Una Kravets的《Finessing
feColorMatrix
》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://alistapart.com/article/finessing-fecolormatrix。
如需转载,烦请注明出处:https://www.fedev.cn/svg/finessing-fecolormatrix.htmlAir Jordan I Mid