1.滤镜工作原理
SVG阅读器处理一个图形对象时,会将对象呈现在位图输出设备上,它可以将对象的描述信息转化为一组对应的像素。在使用滤镜时,SVG阅读器不会直接将图形渲染为最终结果,而是先将像素保存到临时位图中,然后将滤镜指定的操作应用到该临时位图,其结果作为最终图形。
在SVG中,使用filter
元素指定一组操作(也叫基元
),在渲染图形对象时,将该操作应用在最终图形上。
filter标记之间就是我们想要的滤镜基元,每个基元有一个或多个输入,但是只有一个输出,输入可以是原始图形(SourceGraphic
)、图形的阿尔法通道(不透明度,SourceAlpha
)或者是前一个滤镜基元的输出。
2.创建投影效果
filter元素有一些属性用来描述该滤镜的裁剪区域。通过x,y,width,height
属性定义一个滤镜范围,这些属性默认情况是按照对象的边界框计算的,即filterUnits
属性的默认值为objectBoundingBox
,如果要按照用户单位制定边界,则需要设置该属性值为userSpaceOnUse
。
还可以用primitiveUnits
属性为基元操作指定单位,默认值为userSpaceOnUse
,如果设置为objectBoundingBox
则会按照图形尺寸的百分比来表示单位。
使用feGuassianBlur
元素指定一个高斯投影基元。
<defs>
<filter id="gaussian" x="0" y="0">
<feGaussianBlur in="SourceGraphic" stdDeviation="2"></feGaussianBlur>
</filter>
</defs>
<g transform="translate(10,10)">
<rect x="10" y="10" width="100" height="100" fill="#ccc" filter="url(#gaussian)"></rect>
</g>
<g>
<rect x="10" y="10" width="100" height="100" fill="black"></rect>
</g>
在上例中,定义了一个高斯模糊滤镜
,然后通过绘制两次矩形产生矩形阴影效果,但是这要求SVG阅读器要绘制两次矩形,更好的方法时添加多个滤镜基元,让SVG阅读器一次性完成渲染。于是就需要对滤镜结果进行存储、链接以及合并。修改后如下:
<defs>
<filter id="gaussian" x="0" y="0">
<feGaussianBlur in="SourceAlpha" stdDeviation="5" result="blur"></feGaussianBlur>
<feOffset in="blur" dx="10" dy="10" result="offsetBlur"></feOffset>
<feMerge>
<feMergeNode in="offsetBlur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<g>
<rect x="10" y="10" width="100" height="100" fill="black" filter="url(#gaussian)"></rect>
</g>
result
属性指定当前元素的结果稍后可以通过blur引用,这个与id不同,只能在包含该基元的filter中有效。
feOffset
基元接受它的输入,在这里接受的是feGaussianBlur的结果(in="blur"
),偏移由dx和dy指定,输出为offsetBlur
。
feMerge
基元包裹一个feMergeNode
元素列表,每个元素都指定一个输入。这些输入按照出现的顺序叠加
。在这里blur位于原始图形(SourceGraphic)的下面。
3.发光滤镜
feColorMatrix
元素用来以一种通用的方式改变颜色值,可以用来创建一个发光的区域。
<defs>
<filter id="matrix" x="0" y="0">
<feColorMatrix type="matrix" values="
0 0 0 0 0
0 0 0 0.9 0
0 0 0 0.9 0
0 0 0 1 0
"></feColorMatrix>
</filter>
</defs>
<text x="10" y="100" font-size="40" style="filter:url(#matrix)">发光滤镜</text>
feColorMatrix是一个通用的基元,允许修改任意像素点的颜色或阿尔法值,当type="matrix"
时,必须指定一个4x5
的矩阵。矩阵中每行数字分别乘以输入像素的r,g,b,a的值和常量1
,然后加在一起得到输出值。要设置一个变换,将所有不透明区域回执为相同颜色,可以忽略输入颜色和常量。
矩阵模型:
values="
0 0 0 red 0
0 0 0 green 0
0 0 0 blue 0
0 0 0 1 0
"
red,green,blue
的值通常为0到1之间的十进制数,在上述例子中,red为0,green和blue为0.9会产生一个明亮的青色。
上述type为matrxi,除此之外,还有其他三个值:
feColorMatrix基元的type属性 | 说明 |
---|---|
hueRotate | 色相旋转,value是一个单一的数字,描述颜色的色相值应该被旋转多少度 |
saturate | 饱和度,values属性指定一个0到1之间的数字,数字越小,颜色越不饱和 |
luminanceToAlpha | 用亮度决定alpha值,这一属性忽略的values属性值 |
4.feImage滤镜
SVG的feImage滤镜允许使用任意的JPG\PNG\SVG文件或带有id属性SVG元素作为输入源。
<defs>
<filter id="image" x="0" y="0">
<feImage xlink:href="10.0.jpg" result="bg" x="10" y="10" width="200" height="200" preserveAspectRatio="none"></feImage>
</filter>
</defs>
<g style="filter:url(#image)">
<rect x="10" y="10" width="200" height="300" stroke="black"></rect>
</g>
<g>
<rect x="10" y="10" width="200" height="300" fill="none" stroke="black"></rect>
</g>
feImage
基元可以将一个图片作为背景,在上示例中,第一个g元素使用了滤镜,因此可以看到一个200*200的图片。第二个g中包含了一个与第一个g中相同大小的矩形,feImage中定义了图片的尺寸,因此没有填充满第一个矩形。默认情况下feImage元素上使用userSpaceOnUse设置宽度、高度以及x和y,如果要基于滤镜区域,则需要设置filter元素上的primitiveUnits属性为objectBoundingBox。
5.光照效果
可以通过滤镜为图形添加光照效果,添加光照效果必须指定以下信息:
~反射类型:漫反射(feDiffuseLighting
)或镜面反射(feSpecularLighting
)
~想要照亮的对象
~使用的灯光颜色
~想要的光源类型:点光源(fePointLight
),远光(FeFistantLight
)或聚光灯(feSpotLight
)
<defs>
<filter id="diff-light" color-interpolate-filter="sRGB" x="0" y="0">
<feDiffuseLighting in="SourceGraphic"
lighting-color="#ffffcc"
surfaceScale="1"
diffuseConstant="0.5"
result="diffuseOutput">
<fePointLight x="50" y="50" z="20"/>
</feDiffuseLighting>
<feComposite in1="diffuseOutput" in2="SourceGraphic" operator="in" result="diffuseOutput"></feComposite>
<feBlend in1="diffuseOutput" in2="SourceGraphic" mode="screen"></feBlend>
</filter>
</defs>
<circle cx="50" cy="50" r="50" style="filter:url(#diff-light)"></circle>
<circle cx="170" cy="50" r="50" ></circle>
上述示例中使用feDiffuseLighting
定义了一个漫反射元素,设置了光照颜色、计算阿尔法乘积因子(surfaceScale)、RGB值得乘积因子(diffuseConstant)。
fePointLight
元素被包裹在feDiffuseLighting中,定义了光源的相关信息(位置)。
feComposite
元素接受两个源,并指定两个输入的重叠方式。
feBlend
元素也需要两个输入源,还需要一个mode属性指定如何混合输入源。在这里会尝试让图形变亮。
<defs>
<filter id="spec-light" color-interpolate-filter="sRGB" x="0" y="0">
<feSpecularLighting in="SourceGraphic"
lighting-color="#ffffcc"
surfaceScale="1"
specularConstant="1"
specularExponent="4"
result="specOutput"
>
<feDistantLight elevation="25" azimuth="0"/>
</feSpecularLighting>
<feComposite in1="specOutput" in2="SourceGraphic" operator="in" result="specOutput"></feComposite>
<feComposite in1="specOutput" in2="SourceGraphic" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"></feComposite>
</filter>
</defs>
<circle cx="50" cy="50" r="50" style="fill:#060;filter:url(#spec-light)"></circle>
<circle cx="170" cy="50" r="50" style="fill:#060"></circle>
上述例子使用了镜面反射feSpecularLight元素,在feSpecularLight元素中定义了光源颜色、surfaceScale、specularConstant
等属性。与漫反射的光源类型也不同。
6.访问背景
除了SourceGraphic和SourceAlpha作为滤镜输入之外,还可以访问以及渲染到画布上的图片的某一部分,这部分内容称为backgroundImage和backgroundAlpha
。为了访问这些输入信息,滤镜对象必须位于enable-background属性值为new
的容器元素之内。
<defs>
<filter id="blur-background" color-interpolate-filter="sRGB" x="0" y="0">
<feGaussianBlur in="BackgroundImage" stdDeviation="10" result="blur" />
<feComposite in1="blur" in2="SourceGraphic" operator="in"/>
<feOffset dx="4" dy="4" result="offsetBlur"></feOffset>
</filter>
</defs>
<g enable-background="new">
<rect x="20" y="20" width="100" height="100" style="fill:lightblue;stroke:black;stroke-width:10"></rect>
<circle cx="100" cy="100" r="30" style="fill:#fff;filter:url(#blur-background)"></circle>
</g>
在g元素设置enable-background
属性,则它所有的子元素都可以利用背景图像和阿尔法信息。
总结
上述所有滤镜之外,还有好多…写到崩溃(无奈脸)
但是这里只写出了几种常见的滤镜。更多的滤镜相关可以查询相关资料。
作者:xswei
链接:https://github.com/xswei/SVG_Essentials