踏足SVG 深入浅出全方位介绍SVG的功能及特性 - 滤镜篇(一)

前言

基础篇的内容已经全部介绍完毕,下面将会给大家带来 SVG 滤镜的介绍。

在 SVG 当中,滤镜功能无疑是最强大的功能。它让我们对输出的图像可以进行像素级的控制。通过使用一些内置的滤镜功能可以快速达到我们期望的显示效果。

同时,我们也可自己定义图像的输出,以达到一些内置功能没有的或者更强大的功能效果。

本篇文章将介绍什么是滤镜,以及一些简单的内置滤镜效果。

什么是滤镜

滤镜是用于图像的呈现特殊效果的一个工具。通过滤镜我们能够原子级参与图像的显像过程,控制最终的图片输出。

不同的滤镜对外提供了不同的接口,我们可以传入特定的参数来调用滤镜功能,从而实现对图像的显示控制。

如何使用

我们可以看到滤镜特别像一个函数,不同的滤镜对应不同的函数,这些函数的功能已经写好,我们只需要传入参数,调用这些函数,就能实现我们想要的功能。

实际上在 CSS 当中就是通过函数调用的方式去调用滤镜功能的。

fliter in CSS

在 CSS 中通过 fliter 属性,调用内置的滤镜函数调用滤镜功能。以下面图片为例

VIP.png

例:给图片添加模糊效果

.filter-blur{
  filter:blur(5px);
}
复制代码
<img src="../../image/VIP.png" class="filter-blur" alt="">
复制代码

image.png

一行 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);">
复制代码

image.png

在 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的方形区域),该区域内每个方格都有一个权重值。当对图像中的某个像素进行卷积时,我们会把卷积核的中心放置于该图像上,依次计算核中每个元素和其覆盖的图像像素值的乘积并求和,得到的结果就是该位置的新像素值。

卷积.gif

专有属性:

  • in: 标识输入的原语。控制图像输入源。
  • stdDeviation: 定义模糊操作的标准差,值越大越模糊。20以上基本上就看不到了

in 属性

其值可以是下面六种关键词中的一种,或者是一个字符串匹配在同一个<filter>元素中前面的原语的result 属性值. 如果没有提供值并且这是filter中第一个原语,那么原语将相当于使用SourceGraphic作为输入值. 如果没有提供值并且这不是第一个原语,那么原语将使用前面原语的result属性值作为输入.

用人话来说,in 属性可以指定该滤镜所处理图像的图像源。图像源提供了 6 种内置图像模式。如果说该滤镜没有指定 in 属性。那么用用以下原则来确定输入图像。

  1. 如果是 filter 容器定义的首个滤镜元素,没有指定 in 。会用被作用滤镜的元素的图像的 SourceGraphic 模式作为输入源。
  2. 不是首个滤镜元素,会默认以上一个滤镜元素的 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>
复制代码

image.png

一个滤镜容器种多个滤镜元素连续使用

例:滤镜元素默认使用上一个滤镜的快照

<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 并被模糊

image.png

例:控制滤镜元素的输入和输出

<filter id="Filter5">
  <!-- in 默认是原图像的 SourceGraphic -->
  <feOffset dx="10" result="offsetX"/>
  <feGaussianBlur stdDeviation="5" />
  <!-- in 指定使用 offsetX 快照 -->
  <feOffset in="offsetX" dy="10"/>
</filter>
复制代码

最后的结果,没有模糊,图像向 x 和 y 都移动了 10,没有模糊。

image.png

这就是因为滤镜容器的最后一个滤镜元素指定了输入的图像源。feGaussianBlur 滤镜仍然被使用,只不过使用的输出没有被后续滤镜作为输入使用,所以这里 feGaussianBlur 没有效果。

滤镜容器会将最后一个滤镜的输出作为整个滤镜的结果进行输出。

同样的:

<filter id="Filter6">
  <feOffset dx="10" result="offsetX"/>
  <feGaussianBlur stdDeviation="5" />
  <!-- in 指定使用源图像的 SourceGraphic -->
  <feOffset in="SourceGraphic" dy="10"/>
</filter>
复制代码

滤镜输出的结果,只有最后一个滤镜元素有作用。图像向下移动了 10

image.png

feMerge

可以用来对多个滤镜进行叠加。滤镜处理的结果可以用result存储输出。在feMergeNode 元素中访问这些滤镜。feMerge 处理多个 feMergeNode 最后叠加输出

feMergeNode

通过 in 属性来拿到滤镜的处理结果。多个 feMergeNode 最后由 feMerge 完成多个滤镜的叠加输出

实现图像局部高斯效果

局部高斯需要用到 feGaussianBlurfeMergefeMergeNode来实现。

原理上其实是用原始图像和固定大小的区域高斯叠加产生的效果

    <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");
  }
复制代码

image.png

最后

参考资料

参考来源 - MDN

参考来源 - 高斯模糊

猜你喜欢

转载自juejin.im/post/7075205420666585095
SVG
今日推荐