gogoend / blog

blogs, ideas, etc.
MIT License
9 stars 2 forks source link

✨让网页 Bling-Bling 的SVG滤镜 - 图像引入篇 #71

Open gogoend opened 3 years ago

gogoend commented 3 years ago

这是我所写的SVG滤镜相关的第二篇文章。本篇将通过讲解几个原语,来将外部资源引入到SVG滤镜搭建流程中。

图像引入

俗话说,巧妇难为无米之炊。如果说巧妇 === SVG滤镜,那米 === 图像。因此,要想让SVG滤镜发挥作用,我们就需要把要处理的图像传递给SVG滤镜原语中。那么要如何做到这一点呢?

下面我们就来看一些能够为SVG滤镜输入图像的关键字和原语吧

用于对原图像进行引用的关键字

这些关键字可以作为图像处理滤镜原语的in属性的输入值,用来输入图像。

SourceGraphic

表示的是元素在应用滤镜之前本来的样子(源图像)

我们来看一个例子

【例2-1】 这是原图,包含有透明像素。

image.png

为了方便示意,笔者在此亲手绘制了一下棋盘格,由rgba(181,181,181,1)rgba(211,211,211,0.3)两种灰度交错而成,应用滤镜效果的部分仅有gogoend的图案。

【例2-2】 我们来提取原图中的SourceGraphic,即源图像

<filter id="filter">
    <feTile in="SourceGraphic"/>
</filter>

可得到:

image.png

默认情况下,若此处in为空,in的值即为SourceGraphic

SourceAlpha

表示的是元素在应用滤镜之前的透明通道(源图像的Alpha),以灰度图表示

【例2-3】

我们来提取【例2-1】原图中的SourceAlpha,即源图像中的Alpha通道

<filter id="filter">
    <feTile in="SourceAlpha"/>
</filter>

可得到:

image.png

此处全透明像素颜色全白,不透明像素颜色全黑,半透明像素部分为灰色

下方的四个关键字 —— BackgroundImageBackgroundAlphaFillPaintStrokePaint或许可以直接跳过,相关图片仅仅是笔者的猜想而非实际运行结果。

BackgroundImage

~表示当前使用滤镜的元素后方的内容~

经过测试这个原语并不生效。~根据规范所描述,这个原语输出的结果应当为:~

image.png

~由于这里结果是直接叠加在原图上的,且原图没有通过通过其它滤镜引入进来,因此原图应该会直接消失,仅保留背景;而这里留下的背景又和背景成为一体,因此为方便表述,这里画了一个红框。最终拿到的结果即为红框中所框住部分(原先图片下方)的内容(这里是棋盘格),可将提取出的内容交由下一个滤镜原语进行处理。~

BackgroundAlpha

~表示当前使用滤镜的元素后方内容的Alpha通道,以灰度图表示~

经过测试这个原语并不生效。~根据规范所描述,这个原语输出的结果应当为:~

image.png

~这里实际上是输出了棋盘格的Alpha通道。rgba(181,181,181,1)填充部分展示为全白,rgba(211,211,211,0.3)填充部分展示为较暗的灰色~

FillPaint

~表示当前使用滤镜的元素中的填充,取应用滤镜元素的fill属性~

经过测试这个原语并不生效。~根据规范所描述,这个原语输出的结果应当为:~

image.png

~即图像中的填充部分~

StrokePaint

~表示当前使用滤镜的元素中的描边,取应用滤镜元素的stroke属性~

经过测试这个原语并不生效。~根据规范所描述,这个原语输出的结果应当为:~

image.png

~即图像中的描边部分~

很尴尬,经过各种姿势的测试与查阅,BackgroundImageBackgroundAlphaFillPaintStrokePaint四个关键字,在Chrome与Firefox中,似乎都不生效,因此我在此使用删除线划掉了以上描述,与之对应的图片也仅仅是笔者的猜测。虽然规范中规定了这几个值,但浏览器可能并没有对此来进行实现。虽然MDN的这篇文章SVG 1.1 Support in Firefox - SVG: Scalable Vector Graphics“Filter Module”部分大意是说Firefox浏览器实现了这四个关键字中的FillPaintStrokePaint,不过经过笔者实测似乎并没有效果。

你可以打开CodePen来查看这6个关键字的demo。

用于生成图像的滤镜原语

这类原语可以从无到有,或通过引入图像,来生成SVG滤镜的图像源(输入源),可在下方图像处理滤镜元素的in属性中引用。这类原语没有in属性,专用于产生图像。在使用这些原语时,若不通过其它原语使用源图像SourceGraphic,那么源图像将会被替换他们生成的图像替换掉

feFlood - 填充

该原语用于使用某种颜色来对图像进行填充。

【例2-4】

image.png

<filter xmlns="http://www.w3.org/2000/svg" id="filter">
    <feFlood flood-color="#e32247" flood-opacity="1" result="4CD827A1-2842-4D2D-BD12-FCF306D53C5D"/>
</filter>

feImage - 引入外部图像

该原语引入了一个外部图像。

来以近期掘金上活动的logo来做个示例。

如图:

【例2-5】

通过<img>引入SVG,且SVG中的外部图片来自Data URL:

image.png

<filter xmlns="http://www.w3.org/2000/svg" id="filter">
    <feImage href="https://img.bagevent.com/resource/20210610/1714587612971445.png" result="7CA83715-60E2-47AE-AD1F-D30D5C3E5B8D"/>
</filter>

可能你发现了,此处截图和代码中的href值不一致,截图中为baseURL,代码中为http请求的URL。在此笔者解释一下,在制作这个原语的示例时出现了一个坑,当使用SVG图像通过<img>来在HTML中进行引入时,如果SVG中通过<feImage>原语以及<image>元素引入的图片的URL来自网络,则SVG展示时,并不会发起请求来这些外部图片,这就导致外部图片展示为空白;除非你引入的图片的URL为Data URL,否则仅当SVG内联到HTML中或单独展示时,其中<feImage><image>引入的图片才生效。

在这里,左上角缩略图是一张通过<img>标签引入的svg图像,因此发生了这种情况。由于直接在此贴base64 URL太长,因此这里代码中写的是图片的真实URL。下同。

通过<img>SVG引入,且SVG中的外部且图片来自网络请求:

image.png

单独打开SVG:

image.png

<filter xmlns="http://www.w3.org/2000/svg" id="filter">
  <feImage href="https://img.bagevent.com/resource/20210610/1714587612971445.png" result="0A0CDDF8-24B3-40A1-B04D-A581C8A5D1C4"/>
</filter>

【例2-6】将preserveAspectiveRatioalign部分(第一个值)设为none:

image.png

此时图片被拉伸占满了滤镜生效范围。

<filter xmlns="http://www.w3.org/2000/svg" id="filter">
  <feImage href="https://img.bagevent.com/resource/20210610/1714587612971445.png" preserveAspectRatio="none" result="0A0CDDF8-24B3-40A1-B04D-A581C8A5D1C4"/>
</filter>

PS:如果足够细致你应该会发现页面中图片内容没展示全。如果你还记得上篇文章我们所提到的滤镜区域的概念,相信你已经知道为什么了吧~ image.png

【例2-6】将preserveAspectiveRatioalign部分(第一个值)设为其他值,来看看在保持比例的情况下,此处被引入图像如何对齐。

image.png

【例2-7】再将preserveAspectiveRatiomeetOrSlice部分(第二个值)设为slice,来看看此处被引入图像超出滤镜生效范围后将如何对齐。

image.png

feTurbulence - 产生噪波

这一滤镜主要用于产生噪波图像,产生的噪波是包含颜色以及Alpha通道的。

image.png

【例2-6】 这是相关代码,下列示例将在这一代码基础上进行修改:

<filter id="filter1">
    <feTurbulence type="turbulence" baseFrequency="0.02" numOctaves="10" stitchTiles="stitch" seed="0.05" result="B90FB311-12A2-4CAF-AAC7-044B4D4F8043"/>
</filter>
<filter id="filter2">
    <feTurbulence type="fractalNoise" baseFrequency="0.02" numOctaves="10" stitchTiles="stitch" seed="0.05" result="B55AA3B1-8BAC-4260-944C-07FBEFCE37E3"/>
</filter>

image.png

image.png

image.png


好了,以上就是图像引入篇的全部内容了~ 本篇主要介绍的内容是SVG滤镜第一步 —— 图像的引入。正如巧妇有了米,方能做出好吃的饭,在我们有了图像源以后,接下来的流程那自然就是对图像来进行处理啦。尽情关注笔者接下来的其它文章。


总目录:

  1. CSS滤镜篇
  2. 总览篇
  3. 图像引入篇