前言
基础篇的内容已经全部介绍完毕,下面将会给大家带来 SVG 滤镜的介绍。
在 SVG 当中,滤镜功能无疑是最强大的功能。它让我们对输出的图像可以进行像素级的控制。通过使用一些内置的滤镜功能可以快速达到我们期望的显示效果。
同时,我们也可自己定义图像的输出,以达到一些内置功能没有的或者更强大的功能效果。
本篇文章将介绍什么是滤镜,以及一些简单的内置滤镜效果。
什么是滤镜
滤镜是用于图像的呈现特殊效果的一个工具。通过滤镜我们能够原子级参与图像的显像过程,控制最终的图片输出。
不同的滤镜对外提供了不同的接口,我们可以传入特定的参数来调用滤镜功能,从而实现对图像的显示控制。
如何使用
我们可以看到滤镜特别像一个函数,不同的滤镜对应不同的函数,这些函数的功能已经写好,我们只需要传入参数,调用这些函数,就能实现我们想要的功能。
实际上在 CSS 当中就是通过函数调用的方式去调用滤镜功能的。
fliter in CSS
在 CSS 中通过 fliter 属性,调用内置的滤镜函数调用滤镜功能。以下面图片为例
例:给图片添加模糊效果
.filter-blur{
filter:blur(5px);
}
复制代码
<img src="../../image/VIP.png" class="filter-blur" alt="">
复制代码
一行 css 解决,非常的方便。
CSS 提供的内置滤镜有:
- blur 高斯模糊
- brightness 亮度
- contrast 对比度
- drop-shadow 图形阴影
- grayscale 灰度
- hue-rotate 色相旋转
- invert 颜色反转
- opacity 透明度
- saturate 饱和度
- sepia 深褐色滤镜
具体效果可参考mozilla
fliter in SVG
例:用 SVG 的方式实现上述模糊的效果
SVG 元素通过 filter 属性设置滤镜。非 SVG 元素可通过设置 CSS 的 filter 属性用 url 函数引用
<svg width="100" height="100" viewBox="0 0 100 100">
<defs>
<filter id="blur">
<feGaussianBlur stdDeviation="5" />
</filter>
</defs>
<!-- SVG 元素,使用滤镜 -->
<image x="0" y="0" width="100" height="100" xlink:href="../../image/VIP.png" filter="url(#blur)"></image>
</svg>
<!-- 非 SVG 元素,也可以通过设置CSS,调用 SVG 中定义的滤镜效果 -->
<img width="100" height="100" src="../../image/VIP.png" alt="" style="filter: url(#blur);">
复制代码
在 CSS 和 SVG 中都提供了滤镜工具。功能上大径相同,SVG 的滤镜功能提供的更外全面,操作性更强。CSS 的滤镜工具使用上方便,但相对而言灵活性没有 SVG 强大。
CSS 滤镜相对于 SVG 滤镜而言,只提供了部分滤镜功能。CSS 的滤镜效果,都可以通过 SVG 滤镜功能实现。且 SVG 的滤镜功能可以直接在 CSS 中引入使用。
filter 滤镜容器
filter
元素作用是作为原子滤镜操作的容器。它不能直接呈现。可以利用目标SVG元素上的filter
属性引用一个滤镜。
专有属性:
- x: 容器原点 x 坐标
- y: 容器原点 x 坐标
- width: 容器宽度,默认为 120%
- height: 容器高度,默认为 120%
- filterUnits 滤镜容器的坐标系系统
- objectBoundingBox(默认) 以滤镜元素作为坐标系
- userSpaceOnUse 使用滤镜元素所在 SVG 画布的坐标系
- primitiveUnits 滤镜容器内滤镜元素的坐标系系统。
- objectBoundingBox 以滤镜元素作为坐标系
- userSpaceOnUse(默认) 使用滤镜元素所在 SVG 画布的坐标系
filter 容器的坐标系原理同pattern 容器
feGaussianBlur 高斯模糊
该滤镜对输入图像进行高斯模糊
模糊的原理: 当前点的像素色值为轴为8个点的平均值。通常使用卷积的方式对像素进行处理。
在图像处理中,卷积操作指的就是使用一个卷积核(kernel)对一张图像中的每个像素进行一系列操作。卷积核通常是一个四方形网格结构。(例如3X3的方形区域),该区域内每个方格都有一个权重值。当对图像中的某个像素进行卷积时,我们会把卷积核的中心放置于该图像上,依次计算核中每个元素和其覆盖的图像像素值的乘积并求和,得到的结果就是该位置的新像素值。
专有属性:
- in: 标识输入的原语。控制图像输入源。
- stdDeviation: 定义模糊操作的标准差,值越大越模糊。20以上基本上就看不到了
in 属性
其值可以是下面六种关键词中的一种,或者是一个字符串匹配在同一个
<filter>
元素中前面的原语的result
属性值. 如果没有提供值并且这是filter中第一个原语,那么原语将相当于使用SourceGraphic作为输入值. 如果没有提供值并且这不是第一个原语,那么原语将使用前面原语的result属性值作为输入.
用人话来说,in 属性可以指定该滤镜所处理图像的图像源。图像源提供了 6 种内置图像模式。如果说该滤镜没有指定 in 属性。那么用用以下原则来确定输入图像。
- 如果是 filter 容器定义的首个滤镜元素,没有指定 in 。会用被作用滤镜的元素的图像的 SourceGraphic 模式作为输入源。
- 不是首个滤镜元素,会默认以上一个滤镜元素的 result 输出的图像作为输入图像。上一个元素有没有指定 result 名称,并不会有什么影响。result 只是给快照命个名,方便后面单独调取。
对应属性:
- SourceGraphic:使用被作用滤镜元素自身的图像输入
- SourceAlpha:使用被作用滤镜元素自身的图像输入,r、g、b值不被应用,只是用a(透明度)。所以图像时黑色的
- FillPaint:使用被作用滤镜元素自身的图像的填充颜色输入。Firefox 可以看到效果
- StrokePaint:使用被作用滤镜元素自身的图像的描边颜色输入。Firefox 可以看到效果
- BackgroundImage:使用被作用滤镜元素的下层图片作为图像输入。
- BackgroundAlpha:使用被作用滤镜元素的下层图片作为图像输入。r、g、b值不被应用,只是用a(透明度)。所以图像时黑色的
这里需要注意的是 BackgroundImage 和 BackgroundAlpha 各浏览器都没有实现。所以 MDN 用 feBlend
给了一个替代的解决方法
例:SourceGraphic、SourceAlpha、FillPaint、StrokePaint
<svg class="border" width="300" height="500" viewBox="0 0 300 500">
<defs>
<filter id="SourceGraphic">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
</filter>
<filter id="SourceAlpha" >
<feGaussianBlur in="SourceAlpha" stdDeviation="20" />
</filter>
<filter id="FillPaint" >
<feGaussianBlur in="FillPaint" stdDeviation="20" />
</filter>
<filter id="StrokePaint" >
<feGaussianBlur in="StrokePaint" stdDeviation="20" />
</filter>
<filter id="StrokePaint" >
<feGaussianBlur in="StrokePaint" stdDeviation="20" />
</filter>
</defs>
<text x="20" y="20">原图片</text>
<rect x="20" y="30" width="60" height="60" fill="green" stroke="red" stroke-width="3"/>
<text x="20" y="120">SourceGraphic</text>
<rect x="20" y="130" width="60" height="60" fill="green" stroke="red" stroke-width="3" filter="url(#SourceGraphic)"/>
<text x="20" y="220">SourceAlpha</text>
<rect x="20" y="230" width="60" height="60" fill="green" stroke="red" stroke-width="3" filter="url(#SourceAlpha)"/>
<text x="20" y="320">FillPaint</text>
<rect x="20" y="330" width="60" height="60" fill="green" stroke="red" stroke-width="3" filter="url(#FillPaint)"/>
<text x="20" y="420">StrokePaint</text>
<rect x="20" y="430" width="60" height="60" fill="green" stroke="red" stroke-width="3" filter="url(#StrokePaint)"/>
</svg>
复制代码
一个滤镜容器种多个滤镜元素连续使用
例:滤镜元素默认使用上一个滤镜的快照
<svg>
<defs>
<filter id="Filter4">
<!-- in 默认是原图像的 SourceGraphic -->
<feOffset dx="10"/>
<!-- in 默认为使用 feOffset 滤镜后的快照 -->
<feGaussianBlur stdDeviation="5" />
<!-- in 默认为使用 feGaussianBlur 滤镜后的快照 -->
<feOffset dy="10"/>
</filter>
</defs>
</svg>
<div class="border">
<img src="../../image/VIP.png" class="img filter-svg4" alt="" />
</div>
复制代码
.border {
border: 1px solid;
display: inline-block;
}
.filter-svg4{
filter: url("#Filter4");
}
复制代码
最后滤镜的结果由内部定义的滤镜元素共同作用。即输出的图像 x 和 y 都移动了 10 并被模糊
例:控制滤镜元素的输入和输出
<filter id="Filter5">
<!-- in 默认是原图像的 SourceGraphic -->
<feOffset dx="10" result="offsetX"/>
<feGaussianBlur stdDeviation="5" />
<!-- in 指定使用 offsetX 快照 -->
<feOffset in="offsetX" dy="10"/>
</filter>
复制代码
最后的结果,没有模糊,图像向 x 和 y 都移动了 10,没有模糊。
这就是因为滤镜容器的最后一个滤镜元素指定了输入的图像源。feGaussianBlur 滤镜仍然被使用,只不过使用的输出没有被后续滤镜作为输入使用,所以这里 feGaussianBlur 没有效果。
滤镜容器会将最后一个滤镜的输出作为整个滤镜的结果进行输出。
同样的:
<filter id="Filter6">
<feOffset dx="10" result="offsetX"/>
<feGaussianBlur stdDeviation="5" />
<!-- in 指定使用源图像的 SourceGraphic -->
<feOffset in="SourceGraphic" dy="10"/>
</filter>
复制代码
滤镜输出的结果,只有最后一个滤镜元素有作用。图像向下移动了 10
feMerge
可以用来对多个滤镜进行叠加。滤镜处理的结果可以用result存储输出。在feMergeNode 元素中访问这些滤镜。feMerge 处理多个 feMergeNode 最后叠加输出
feMergeNode
通过 in 属性来拿到滤镜的处理结果。多个 feMergeNode 最后由 feMerge 完成多个滤镜的叠加输出
实现图像局部高斯效果
局部高斯需要用到 feGaussianBlur
、feMerge
、feMergeNode
来实现。
原理上其实是用原始图像和固定大小的区域高斯叠加产生的效果
<svg width="100" height="100" viewBox="0 0 100 100">
<defs>
<filter id="MyFilter2">
<!-- 定义模糊的位置和大小,通过 result 输入快照-->
<feGaussianBlur x="25" y="25" width="50%" height="50%" stdDeviation="5" result="blur" />
<!-- merge 合成,将 blur 快照与原图像进行叠加-->
<feMerge>
<!-- 这里顺序很重要,由于是叠加,所以原始图像先放原始图像,在放局部高斯图像 -->
<feMergeNode in="SourceGraphic" />
<feMergeNode in="blur" />
</feMerge>
</filter>
</defs>
<image width="100" height="100" href="../../image/VIP.png" filter="url(#MyFilter2)"></image>
</svg>
<!-- 在 svg 外部使用 -->
<img src="../../image/VIP.png" class="img filter-svg_part" alt="" />
复制代码
.img {
display: block;
width: 100px;
height: 100px;
}
.filter-svg_part{
filter: url("#MyFilter2");
}
复制代码
最后
参考资料