本章介绍了 SVG 的声明式滤镜效果功能集,将其与 SVG 的 2D 处理能力相结合,可以描述 Web 上许多常见的图形,并能轻松实现客户端的生成与修改。此外,能够将滤镜效果应用于 SVG 图形元素 和 容器元素,有助于保持文档的语义结构,而无需诉诸图像。图像不仅通常是固定分辨率的,而且往往会掩盖它们所替代元素的原始语义。对于应用于文本的效果而言尤其如此。
滤镜效果由一系列应用于给定 源图形 的图形操作组成,以产生修改后的图形结果。滤镜效果的结果将渲染到目标设备,而不是渲染原始源图形。下图说明了此过程

滤镜效果由 ‘filter’ 元素定义。要将滤镜效果应用于 图形元素 或 容器元素,您需要在给定元素上设置 ‘filter’ 属性的值,使其引用该滤镜效果。
每个 ‘filter’ 元素包含一组 滤镜基元 作为其子元素。每个滤镜基元对一个或多个输入执行单一的基础图形操作(例如,模糊或光照效果),从而产生一个图形结果。由于大多数滤镜基元代表某种形式的图像处理,在大多数情况下,滤镜基元的输出是一个单一的 RGBA 图像。
原始源图形或过滤原语的结果可作为一个或多个其他过滤原语的输入。常见的做法是多次使用源图形。例如,一个简单的过滤器可以通过添加偏移的原始源图形的黑色副本来生成投影阴影,从而将一个图形变为两个。实际上,这会产生两层图形,均使用相同的原始源图形。
当应用于 容器元素(如 ‘g’)时,‘filter’ 属性会应用于整个组的内容。组的子元素不会直接渲染到屏幕上;相反,渲染子元素所需的图形命令会被临时存储。通常,图形命令是通过使用 SourceGraphic 或 SourceAlpha 关键字,作为对所引用的 ‘filter’ 元素进行处理的一部分来执行的。滤镜效果可以应用于没有内容的 容器元素(例如一个空的 ‘g’ 元素),在这种情况下,SourceGraphic 或 SourceAlpha 由一个透明的黑色矩形组成,其大小为 滤镜效果区域。
有时滤镜基元会导致未定义的像素。例如,滤镜基元 ‘feOffset’ 可以将图像向右下方移动,从而在顶部和左侧留下未定义的像素。在这些情况下,未定义的像素被设置为透明黑色。
下面展示了一个过滤效果的示例。
示例 filters01 - 介绍过滤效果。
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"https://w3org.cn/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="7.5cm" height="5cm" viewBox="0 0 200 120"
xmlns="https://w3org.cn/2000/svg" version="1.1">
<title>Example filters01.svg - introducing filter effects</title>
<desc>An example which combines multiple filter primitives
to produce a 3D lighting effect on a graphic consisting
of the string "SVG" sitting on top of oval filled in red
and surrounded by an oval outlined in red.</desc>
<defs>
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="200" height="120">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
<feOffset in="blur" dx="4" dy="4" result="offsetBlur"/>
<feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75"
specularExponent="20" lighting-color="#bbbbbb"
result="specOut">
<fePointLight x="-5000" y="-10000" z="20000"/>
</feSpecularLighting>
<feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
<feComposite in="SourceGraphic" in2="specOut" operator="arithmetic"
k1="0" k2="1" k3="1" k4="0" result="litPaint"/>
<feMerge>
<feMergeNode in="offsetBlur"/>
<feMergeNode in="litPaint"/>
</feMerge>
</filter>
</defs>
<rect x="1" y="1" width="198" height="118" fill="#888888" stroke="blue" />
<g filter="url(#MyFilter)" >
<g>
<path fill="none" stroke="#D90000" stroke-width="10"
d="M50,90 C0,90 0,30 50,30 L150,30 C200,30 200,90 150,90 z" />
<path fill="#D90000"
d="M60,80 C30,80 30,40 60,40 L140,40 C170,40 170,80 140,80 z" />
<g fill="#FFFFFF" stroke="black" font-size="45" font-family="Verdana" >
<text x="52" y="76">SVG</text>
</g>
</g>
</g>
</svg>![]() |
上面示例中使用的滤镜效果在此处重复,在六个滤镜原语中的每一个之前,左侧列出了参考编号
1 2 3 4 5 6 |
<filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="200" height="120">
<desc>Produces a 3D lighting effect.</desc>
<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
<feOffset in="blur" dx="4" dy="4" result="offsetBlur"/>
<feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75"
specularExponent="20" lighting-color="#bbbbbb"
result="specOut">
<fePointLight x="-5000" y="-10000" z="20000"/>
</feSpecularLighting>
<feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
<feComposite in="SourceGraphic" in2="specOut" operator="arithmetic"
k1="0" k2="1" k3="1" k4="0" result="litPaint"/>
<feMerge>
<feMergeNode in="offsetBlur"/>
<feMergeNode in="litPaint"/>
</feMerge>
</filter>
|
下图显示了六个滤镜元素中每一个的中间图像结果
|
|
|
|
| |||
|
|
|
|
‘filter’ 元素的描述如下
属性定义
属性从其祖先继承到 ‘filter’ 元素中;属性不从引用 ‘filter’ 元素的元素继承。
‘filter’ 元素永远不会被直接渲染;它们唯一的用途是被 ‘filter’ 属性引用的对象。‘display’ 属性不适用于 ‘filter’ 元素;因此,即使 ‘display’ 属性设置为非 none 的值,‘filter’ 元素也不会被直接渲染,并且即使 ‘filter’ 元素或其任何祖先上的 ‘display’ 属性被设置为 none,‘filter’ 元素仍然可供引用。
‘filter’ 属性的描述如下
‘filter’ 元素可以定义画布上的一个区域,该区域应用给定的滤镜效果,并可以为用于处理任何基于光栅的滤镜基元的任何中间连续色调图像提供分辨率。‘filter’ 元素具有以下属性,这些属性共同定义了滤镜效果区域
定义属性 ‘x’, ‘y’, ‘width’ 和 ‘height’ 的坐标系。
如果 filterUnits="userSpaceOnUse",则 ‘x’, ‘y’, ‘width’ 和 ‘height’ 代表在引用 ‘filter’ 时(即通过 ‘filter’ 属性引用 ‘filter’ 的元素的当前用户坐标系)生效的当前用户坐标系中的值。
如果 filterUnits="objectBoundingBox",则 ‘x’, ‘y’, ‘width’ 和 ‘height’ 代表引用元素边界框的分数或百分比(参见 对象边界框单位)。
如果未指定 ‘filterUnits’ 属性,则效果如同指定了 'objectBoundingBox' 一样。
可动画:是。
这些属性定义了此滤镜应用的画布上的矩形区域。
应用滤镜所需的内存量和处理时间与此矩形的大小以及滤镜的 ‘filterRes’ 属性有关。
这些属性的坐标系取决于 ‘filterUnits’ 属性的值。
‘width’ 或 ‘height’ 的负值是错误的(参见 错误处理)。零值会禁用引用滤镜的元素的渲染。
此矩形的边界对于给定 ‘filter’ 元素中包含的每个 滤镜基元 而言都充当严格的剪切区域;因此,如果给定滤镜基元的效果超出了矩形的边界(这有时在使用带有非常大 ‘stdDeviation’ 的 ‘feGaussianBlur’ 滤镜基元时发生),效果的部分内容将被剪切。
如果未指定 ‘x’ 或 ‘y’,则效果如同指定了 -10% 一样。
如果未指定 ‘width’ 或 ‘height’,则效果如同指定了 120% 一样。
可动画:是。
此属性采用 x-pixels [y-pixels] 的形式,指示中间图像的像素宽度和高度。如果未提供,则用户代理将使用合理的值在输出设备上产生高质量的结果。
为此属性分配非默认值时应小心。过小的值可能会导致结果中出现不希望的像素化。过大的值可能会导致处理缓慢和大量内存使用。
负值是错误的(参见 错误处理)。零值会禁用引用滤镜的元素的渲染。
非整数值会被截断,即向零取整到最接近的整数值。
可动画:是。
请注意,‘filterUnits’ 的两个可能值(即 'objectBoundingBox' 和 'userSpaceOnUse')都会导致滤镜区域的坐标系,其 X 轴和 Y 轴分别平行于将要应用滤镜的元素的用户坐标系的 X 轴和 Y 轴。
有时,当 滤镜区域 可以直接映射到设备像素时,实现者可以获得更快的性能;因此,为了在显示设备上获得最佳性能,建议作者定义其区域,以便 SVG 用户代理可以将 滤镜区域 与背景进行逐像素对齐。特别是,为了获得最佳滤镜效果性能,请避免旋转或倾斜用户坐标系。‘filterRes’ 属性的显式值可能会帮助或损害性能。如果 ‘filterRes’ 小于自动(即默认)滤镜分辨率,则滤镜效果的性能可能会更快(通常以牺牲质量为代价)。如果 ‘filterRes’ 大于自动(即默认)滤镜分辨率,则滤镜效果的性能通常会变慢。
通常需要提供填充空间,因为滤镜效果可能会影响给定对象紧密贴合的边界框之外的位。出于这些目的,可以为 ‘x’ 和 ‘y’ 提供负百分比值,并为 ‘width’ 和 ‘height’ 提供大于 100% 的百分比值。例如,这就是为什么滤镜效果区域的默认值为 x="-10%" y="-10%" width="120%" height="120%" 的原因。
滤镜效果的两个可能的伪输入图像是 BackgroundImage 和 BackgroundAlpha,它们各自代表在调用 ‘filter’ 元素时,滤镜区域下画布的图像快照。BackgroundImage 代表画布的颜色值和 Alpha 通道(即 RGBA 像素值),而 BackgroundAlpha 仅代表 Alpha 通道。
SVG 用户代理的实现通常需要维护补充背景图像缓冲区,以支持 BackgroundImage 和 BackgroundAlpha 伪输入图像。有时,背景图像缓冲区将包含当前画布上累积绘图操作的内存副本。
由于内存中的图像缓冲区会占用大量系统资源,因此 SVG 内容必须明确向 SVG 用户代理指示文档在可以使用 BackgroundImage 和 BackgroundAlpha 伪输入图像之前需要访问背景图像。启用对背景图像访问的属性是 ‘enable-background’,定义如下
‘enable-background’ 仅适用于 容器元素,并指定 SVG 用户代理如何管理背景图像的累积。
new 值指示两件事
enable-background: accumulate(初始/默认值)的含义取决于上下文
如果滤镜效果指定了 BackgroundImage 或 BackgroundAlpha 伪输入图像,并且没有任何祖先 容器元素 的属性值为 enable-background: new,则背景图像请求在技术上是错误的。处理将继续而不中断(即没有错误消息),并将提供透明黑色图像以响应请求。
new 值上的可选 <x>,<y>,<width>,<height> 参数是 <number> 值,用于指示允许发生背景图像访问的 容器元素 的 用户空间 子区域。这些参数使 SVG 用户代理可能分配比默认值更小的临时图像缓冲区。因此,值 <x>,<y>,<width>,<height> 在背景图像画布上充当剪切矩形。<width> 或 <height> 的负值是错误的(参见 错误处理)。如果指定了大于零但小于四个 <x>,<y>,<width> 和 <height> 的值,或者如果为 <width> 或 <height> 指定了零值,则 BackgroundImage 和 BackgroundAlpha 的处理如同未启用背景图像处理一样。
假设您在文档中有一个元素 E,并且 E 有一系列祖先 A1(其直接父级)、A2 等。(注意:A0 是 E。)每个祖先 Ai 都将有一个相应的临时背景图像离屏缓冲区 BUFi。E 引用的 ‘filter’ 可用的 背景图像 内容定义如下
示例 enable-background-01 说明了背景图像处理的规则。
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"https://w3org.cn/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="13.5cm" height="2.7cm" viewBox="0 0 1350 270"
xmlns="https://w3org.cn/2000/svg" version="1.1">
<title>Example enable-background01</title>
<desc>This test case shows five pictures which illustrate the rules
for background image processing.</desc>
<defs>
<filter id="ShiftBGAndBlur"
filterUnits="userSpaceOnUse" x="0" y="0" width="1200" height="400">
<desc>
This filter discards the SourceGraphic, if any, and just produces
a result consisting of the BackgroundImage shifted down 125 units
and then blurred.
</desc>
<feOffset in="BackgroundImage" dx="0" dy="125" />
<feGaussianBlur stdDeviation="8" />
</filter>
<filter id="ShiftBGAndBlur_WithSourceGraphic"
filterUnits="userSpaceOnUse" x="0" y="0" width="1200" height="400">
<desc>
This filter takes the BackgroundImage, shifts it down 125 units, blurs it,
and then renders the SourceGraphic on top of the shifted/blurred background.
</desc>
<feOffset in="BackgroundImage" dx="0" dy="125" />
<feGaussianBlur stdDeviation="8" result="blur" />
<feMerge>
<feMergeNode in="blur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<g transform="translate(0,0)">
<desc>The first picture is our reference graphic without filters.</desc>
<rect x="25" y="25" width="100" height="100" fill="red"/>
<g opacity=".5">
<circle cx="125" cy="75" r="45" fill="green"/>
<polygon points="160,25 160,125 240,75" fill="blue"/>
</g>
<rect x="5" y="5" width="260" height="260" fill="none" stroke="blue"/>
</g>
<g enable-background="new" transform="translate(270,0)">
<desc>The second adds an empty 'g' element which invokes ShiftBGAndBlur.</desc>
<rect x="25" y="25" width="100" height="100" fill="red"/>
<g opacity=".5">
<circle cx="125" cy="75" r="45" fill="green"/>
<polygon points="160,25 160,125 240,75" fill="blue"/>
</g>
<g filter="url(#ShiftBGAndBlur)"/>
<rect x="5" y="5" width="260" height="260" fill="none" stroke="blue"/>
</g>
<g enable-background="new" transform="translate(540,0)">
<desc>The third invokes ShiftBGAndBlur on the inner group.</desc>
<rect x="25" y="25" width="100" height="100" fill="red"/>
<g filter="url(#ShiftBGAndBlur)" opacity=".5">
<circle cx="125" cy="75" r="45" fill="green"/>
<polygon points="160,25 160,125 240,75" fill="blue"/>
</g>
<rect x="5" y="5" width="260" height="260" fill="none" stroke="blue"/>
</g>
<g enable-background="new" transform="translate(810,0)">
<desc>The fourth invokes ShiftBGAndBlur on the triangle.</desc>
<rect x="25" y="25" width="100" height="100" fill="red"/>
<g opacity=".5">
<circle cx="125" cy="75" r="45" fill="green"/>
<polygon points="160,25 160,125 240,75" fill="blue"
filter="url(#ShiftBGAndBlur)"/>
</g>
<rect x="5" y="5" width="260" height="260" fill="none" stroke="blue"/>
</g>
<g enable-background="new" transform="translate(1080,0)">
<desc>The fifth invokes ShiftBGAndBlur_WithSourceGraphic on the triangle.</desc>
<rect x="25" y="25" width="100" height="100" fill="red"/>
<g opacity=".5">
<circle cx="125" cy="75" r="45" fill="green"/>
<polygon points="160,25 160,125 240,75" fill="blue"
filter="url(#ShiftBGAndBlur_WithSourceGraphic)"/>
</g>
<rect x="5" y="5" width="260" height="260" fill="none" stroke="blue"/>
</g>
</svg>![]() |
上面的示例包含五个部分,描述如下
本节介绍了可以组合以实现特定滤镜效果的各种滤镜基元。
除非另有说明,否则所有图像滤镜均在预乘 RGBA 样本上运行。在非预乘数据上工作更自然的滤镜(feColorMatrix 和 feComponentTransfer)将按照规定暂时撤销和重做预乘。所有光栅效果过滤操作接收 1 到 N 个输入 RGBA 图像,以及附加属性作为参数,并产生一个单一的输出 RGBA 图像。
每个滤镜基元的 RGBA 结果将被限制在颜色和不透明度值的允许范围内。因此,例如,给定滤镜基元的结果将把任何负的颜色值或不透明度值调整为零的颜色/不透明度。
特定滤镜基元执行其操作的颜色空间由该滤镜基元上 ‘color-interpolation-filters’ 属性的值决定。另一个属性 ‘color-interpolation’ 确定其他颜色操作的颜色空间。因为这两个属性具有不同的初始值(‘color-interpolation-filters’ 的初始值为 linearRGB,而 ‘color-interpolation’ 的初始值为 sRGB),在某些情况下为了达到特定的结果(例如,当协调渐变插值与过滤操作时),将需要在特定元素上明确设置 ‘color-interpolation’ 为 linearRGB 或 ‘color-interpolation-filters’ 为 sRGB。请注意,下面的示例没有显式设置 ‘color-interpolation’ 或 ‘color-interpolation-filters’,因此这些属性的初始值适用于这些示例。
除了 ‘in’ 属性外,以下所有属性都可在所有滤镜基元元素上使用
属性定义
‘in’ 属性可在所有需要输入的滤镜基元元素上使用。
可动画:是。所有滤镜基元都具有属性 ‘x’, ‘y’, ‘width’ 和 ‘height’,它们标识了限制给定滤镜基元的计算和渲染的子区域。这些属性根据与其他滤镜基元的坐标和长度属性相同的规则定义,因此代表由 ‘filter’ 元素上的 ‘primitiveUnits’ 属性建立的坐标系中的值。
‘x’, ‘y’, ‘width’ 和 ‘height’ 默认为为所有被引用节点定义的子区域的并集(即最紧密贴合的边界框)。如果没有引用节点(例如对于 ‘feImage’ 或 ‘feTurbulence’),或者一个或多个被引用节点是标准输入(SourceGraphic, SourceAlpha, BackgroundImage, BackgroundAlpha, FillPaint 或 StrokePaint 中的一个),或者对于 ‘feTile’(它很特殊,因为其主要功能是在 X 和 Y 方向上复制被引用节点,从而产生通常更大的结果),默认子区域为 0%,0%,100%,100%,其中百分比作为特殊情况相对于 滤镜区域 的维度,从而使默认 滤镜基元子区域 等于 滤镜区域。
‘x’, ‘y’, ‘width’ 和 ‘height’ 在滤镜基元的输入图像和滤镜基元结果上都充当硬剪切矩形。
定义所有中间离屏缓冲区不超过 ‘x’, ‘y’, ‘width’ 和 ‘height’ 与 滤镜区域 的交集。滤镜区域 和任何 ‘x’, ‘y’, ‘width’ 和 ‘height’ 子区域应被设置为使得所有离屏缓冲区足够大,以容纳任何部分与 滤镜区域 或 x,y,width,height 子区域相交的像素。
‘feTile’ 引用前一个滤镜基元,然后根据被引用滤镜基元的 ‘x’, ‘y’, ‘width’ 和 ‘height’ 值将拼贴(tiles)缝合在一起,以填充其自身的 滤镜基元子区域。
示例 primitive-subregion-01 展示了指定滤镜基元子区域的效果
<svg width="400" height="400" xmlns="https://w3org.cn/2000/svg">
<defs>
<filter id="flood" x="0" y="0" width="100%" height="100%" primitiveUnits="objectBoundingBox">
<feFlood x="25%" y="25%" width="50%" height="50%"
flood-color="green" flood-opacity="0.75"/>
</filter>
<filter id="blend" primitiveUnits="objectBoundingBox">
<feBlend x="25%" y="25%" width="50%" height="50%"
in2="SourceGraphic" mode="multiply"/>
</filter>
<filter id="merge" primitiveUnits="objectBoundingBox">
<feMerge x="25%" y="25%" width="50%" height="50%">
<feMergeNode in="SourceGraphic"/>
<feMergeNode in="FillPaint"/>
</feMerge>
</filter>
</defs>
<g fill="none" stroke="blue" stroke-width="4">
<rect width="200" height="200"/>
<line x2="200" y2="200"/>
<line x1="200" y2="200"/>
</g>
<circle fill="green" filter="url(#flood)" cx="100" cy="100" r="90"/>
<g transform="translate(200 0)">
<g fill="none" stroke="blue" stroke-width="4">
<rect width="200" height="200"/>
<line x2="200" y2="200"/>
<line x1="200" y2="200"/>
</g>
<circle fill="green" filter="url(#blend)" cx="100" cy="100" r="90"/>
</g>
<g transform="translate(0 200)">
<g fill="none" stroke="blue" stroke-width="4">
<rect width="200" height="200"/>
<line x2="200" y2="200"/>
<line x1="200" y2="200"/>
</g>
<circle fill="green" fill-opacity="0.5" filter="url(#merge)" cx="100" cy="100" r="90"/>
</g>
</svg>![]() |
在上面的示例中,有三个矩形,每个矩形中都有一个十字和一个圆圈。每个圆圈元素都应用了不同的滤镜,但具有相同的 滤镜基元子区域。滤镜输出应限制在 滤镜基元子区域 内,因此您不应该看到圆圈本身,只能看到构成 滤镜基元子区域 的矩形。
以下各节定义了定义光源的元素 ‘feDistantLight’, ‘fePointLight’ 和 ‘feSpotLight’,以及定义光颜色的 ‘lighting-color’ 属性。
属性定义
下图说明了 ‘azimuth’ 和 ‘elevation’ 在 XYZ 坐标系中代表的角度。
属性定义
属性定义
‘lighting-color’ 属性定义滤镜基元 ‘feDiffuseLighting’ 和 ‘feSpecularLighting’ 的光源颜色。
| 值 | currentColor | <color> [<icccolor>] | inherit |
| 初始值 | white (白色) |
| 应用于 | ‘feDiffuseLighting’ 和 ‘feSpecularLighting’ 元素 |
| 可继承 | 否 |
| 百分比 | 不适用 |
| 媒体 | 视觉 |
| 可动画: | 是 |
此滤镜使用常用的图像软件混合模式将两个对象合成在一起。它对两个输入图像执行逐像素组合。
属性定义
对于所有 feBlend 模式,结果不透明度的计算如下
qr = 1 - (1-qa)*(1-qb)
对于下面的合成公式,应用以下定义
cr = Result color (RGB) - premultiplied qa = Opacity value at a given pixel for image A qb = Opacity value at a given pixel for image B ca = Color (RGB) at a given pixel for image A - premultiplied cb = Color (RGB) at a given pixel for image B - premultiplied
下表提供了可用图像混合模式的列表
| 图像混合模式 | 计算结果颜色的公式 |
| normal | cr = (1 - qa) * cb + ca |
| multiply | cr = (1-qa)*cb + (1-qb)*ca + ca*cb |
| screen | cr = cb + ca - ca * cb |
| darken | cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb) |
| lighten | cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb) |
'normal' 混合模式等效于 ‘feComposite’ 滤镜基元上的 operator="over",匹配 ‘feMerge’ 使用的混合方法,并匹配 SVG 中用于滤镜效果之外所有合成的 简单 Alpha 合成 技术。
示例 feBlend 展示了五种混合模式的示例。
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"https://w3org.cn/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="5cm" height="5cm" viewBox="0 0 500 500"
xmlns="https://w3org.cn/2000/svg" version="1.1">
<title>Example feBlend - Examples of feBlend modes</title>
<desc>Five text strings blended into a gradient,
with one text string for each of the five feBlend modes.</desc>
<defs>
<linearGradient id="MyGradient" gradientUnits="userSpaceOnUse"
x1="100" y1="0" x2="300" y2="0">
<stop offset="0" stop-color="#000000" />
<stop offset=".33" stop-color="#ffffff" />
<stop offset=".67" stop-color="#ff0000" />
<stop offset="1" stop-color="#808080" />
</linearGradient>
<filter id="Normal">
<feBlend mode="normal" in2="BackgroundImage" in="SourceGraphic"/>
</filter>
<filter id="Multiply">
<feBlend mode="multiply" in2="BackgroundImage" in="SourceGraphic"/>
</filter>
<filter id="Screen">
<feBlend mode="screen" in2="BackgroundImage" in="SourceGraphic"/>
</filter>
<filter id="Darken">
<feBlend mode="darken" in2="BackgroundImage" in="SourceGraphic"/>
</filter>
<filter id="Lighten">
<feBlend mode="lighten" in2="BackgroundImage" in="SourceGraphic"/>
</filter>
</defs>
<rect fill="none" stroke="blue"
x="1" y="1" width="498" height="498"/>
<g enable-background="new" >
<rect x="100" y="20" width="300" height="460" fill="url(#MyGradient)" />
<g font-family="Verdana" font-size="75" fill="#888888" fill-opacity=".6" >
<text x="50" y="90" filter="url(#Normal)" >Normal</text>
<text x="50" y="180" filter="url(#Multiply)" >Multiply</text>
<text x="50" y="270" filter="url(#Screen)" >Screen</text>
<text x="50" y="360" filter="url(#Darken)" >Darken</text>
<text x="50" y="450" filter="url(#Lighten)" >Lighten</text>
</g>
</g>
</svg>![]() |
此滤镜应用矩阵变换
| R' | | a00 a01 a02 a03 a04 | | R | | G' | | a10 a11 a12 a13 a14 | | G | | B' | = | a20 a21 a22 a23 a24 | * | B | | A' | | a30 a31 a32 a33 a34 | | A | | 1 | | 0 0 0 0 1 | | 1 |
对输入图形上每个像素的 RGBA 颜色和 alpha 值进行处理,以产生一组新的 RGBA 颜色和 alpha 值结果。
计算是在非预乘颜色值上执行的。如果输入图形由预乘颜色值组成,则这些值会自动转换为此操作的非预乘颜色值。
这些矩阵通常在 Alpha 通道中执行恒等映射。如果是这种情况,实现可以避免对所有 A = 1 的像素进行昂贵的撤销和重做预乘。
属性定义
type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"
| R' | |0.213+0.787s 0.715-0.715s 0.072-0.072s 0 0 | | R | | G' | |0.213-0.213s 0.715+0.285s 0.072-0.072s 0 0 | | G | | B' | = |0.213-0.213s 0.715-0.715s 0.072+0.928s 0 0 | * | B | | A' | | 0 0 0 1 0 | | A | | 1 | | 0 0 0 0 1 | | 1 |
| R' | | a00 a01 a02 0 0 | | R | | G' | | a10 a11 a12 0 0 | | G | | B' | = | a20 a21 a22 0 0 | * | B | | A' | | 0 0 0 1 0 | | A | | 1 | | 0 0 0 0 1 | | 1 |其中项 a00, a01 等计算如下
| a00 a01 a02 | [+0.213 +0.715 +0.072]
| a10 a11 a12 | = [+0.213 +0.715 +0.072] +
| a20 a21 a22 | [+0.213 +0.715 +0.072]
[+0.787 -0.715 -0.072]
cos(hueRotate value) * [-0.213 +0.285 -0.072] +
[-0.213 -0.715 +0.928]
[-0.213 -0.715+0.928]
sin(hueRotate value) * [+0.143 +0.140-0.283]
[-0.787 +0.715+0.072]
因此,色相矩阵的左上项变为.213 + cos(hueRotate value)*.787 - sin(hueRotate value)*.213
| R' | | 0 0 0 0 0 | | R | | G' | | 0 0 0 0 0 | | G | | B' | = | 0 0 0 0 0 | * | B | | A' | | 0.2125 0.7154 0.0721 0 0 | | A | | 1 | | 0 0 0 0 1 | | 1 |
示例 feColorMatrix 展示了四种 feColorMatrix 操作的示例。
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"https://w3org.cn/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="8cm" height="5cm" viewBox="0 0 800 500"
xmlns="https://w3org.cn/2000/svg" version="1.1">
<title>Example feColorMatrix - Examples of feColorMatrix operations</title>
<desc>Five text strings showing the effects of feColorMatrix:
an unfiltered text string acting as a reference,
use of the feColorMatrix matrix option to convert to grayscale,
use of the feColorMatrix saturate option,
use of the feColorMatrix hueRotate option,
and use of the feColorMatrix luminanceToAlpha option.</desc>
<defs>
<linearGradient id="MyGradient" gradientUnits="userSpaceOnUse"
x1="100" y1="0" x2="500" y2="0">
<stop offset="0" stop-color="#ff00ff" />
<stop offset=".33" stop-color="#88ff88" />
<stop offset=".67" stop-color="#2020ff" />
<stop offset="1" stop-color="#d00000" />
</linearGradient>
<filter id="Matrix" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feColorMatrix type="matrix" in="SourceGraphic"
values=".33 .33 .33 0 0
.33 .33 .33 0 0
.33 .33 .33 0 0
.33 .33 .33 0 0"/>
</filter>
<filter id="Saturate40" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feColorMatrix type="saturate" in="SourceGraphic" values="0.4"/>
</filter>
<filter id="HueRotate90" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feColorMatrix type="hueRotate" in="SourceGraphic" values="90"/>
</filter>
<filter id="LuminanceToAlpha" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feColorMatrix type="luminanceToAlpha" in="SourceGraphic" result="a"/>
<feComposite in="SourceGraphic" in2="a" operator="in" />
</filter>
</defs>
<rect fill="none" stroke="blue"
x="1" y="1" width="798" height="498"/>
<g font-family="Verdana" font-size="75"
font-weight="bold" fill="url(#MyGradient)" >
<rect x="100" y="0" width="500" height="20" />
<text x="100" y="90">Unfiltered</text>
<text x="100" y="190" filter="url(#Matrix)" >Matrix</text>
<text x="100" y="290" filter="url(#Saturate40)" >Saturate</text>
<text x="100" y="390" filter="url(#HueRotate90)" >HueRotate</text>
<text x="100" y="490" filter="url(#LuminanceToAlpha)" >Luminance</text>
</g>
</svg>![]() |
此滤镜原语执行组件级数据重映射,如下所示
R' = feFuncR( R ) G' = feFuncG( G ) B' = feFuncB( B ) A' = feFuncA( A )
针对每个像素。它允许进行亮度调整、对比度调整、色彩平衡或阈值处理等操作。
计算是在非预乘颜色值上执行的。如果输入图形由预乘颜色值组成,则这些值会自动转换为此操作的非预乘颜色值。(请注意,如果 feFuncA 是恒等变换且源图形上的所有 Alpha 值都设置为 1,则可以避免撤销和重做预乘。)
‘feComponentTransfer’ 元素的子元素指定了四个通道的传递函数
以下规则适用于 ‘feComponentTransfer’ 元素的处理
下面的属性是 传递函数元素属性,它们适用于定义传递函数的子元素 ‘feFuncR’, ‘feFuncG’, ‘feFuncB’ 和 ‘feFuncA’。
属性定义
指明组件传输函数的类型。函数类型决定了其他属性的适用性。
在下面中,C 是初始分量(例如 ‘feFuncR’),C' 是重映射后的分量;两者都在闭区间 [0,1] 内。
C' = C
对于值 C < 1,寻找 k 使得
k/n <= C < (k+1)/n
结果 C' 由下式给出
C' = vk + (C - k/n)*n * (vk+1 - vk)
如果 C = 1 则
C' = vn。
对于值 C < 1,寻找 k 使得
k/n <= C < (k+1)/n
结果 C' 由下式给出
C' = vk
如果 C = 1 则
C' = vn-1。
示例 feComponentTransfer 展示了四种 feComponentTransfer 操作的示例。
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"https://w3org.cn/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="8cm" height="4cm" viewBox="0 0 800 400"
xmlns="https://w3org.cn/2000/svg" version="1.1">
<title>Example feComponentTransfer - Examples of feComponentTransfer operations</title>
<desc>Four text strings showing the effects of feComponentTransfer:
an identity function acting as a reference,
use of the feComponentTransfer table option,
use of the feComponentTransfer linear option,
and use of the feComponentTransfer gamma option.</desc>
<defs>
<linearGradient id="MyGradient" gradientUnits="userSpaceOnUse"
x1="100" y1="0" x2="600" y2="0">
<stop offset="0" stop-color="#ff0000" />
<stop offset=".33" stop-color="#00ff00" />
<stop offset=".67" stop-color="#0000ff" />
<stop offset="1" stop-color="#000000" />
</linearGradient>
<filter id="Identity" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feComponentTransfer>
<feFuncR type="identity"/>
<feFuncG type="identity"/>
<feFuncB type="identity"/>
<feFuncA type="identity"/>
</feComponentTransfer>
</filter>
<filter id="Table" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feComponentTransfer>
<feFuncR type="table" tableValues="0 0 1 1"/>
<feFuncG type="table" tableValues="1 1 0 0"/>
<feFuncB type="table" tableValues="0 1 1 0"/>
</feComponentTransfer>
</filter>
<filter id="Linear" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feComponentTransfer>
<feFuncR type="linear" slope=".5" intercept=".25"/>
<feFuncG type="linear" slope=".5" intercept="0"/>
<feFuncB type="linear" slope=".5" intercept=".5"/>
</feComponentTransfer>
</filter>
<filter id="Gamma" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feComponentTransfer>
<feFuncR type="gamma" amplitude="2" exponent="5" offset="0"/>
<feFuncG type="gamma" amplitude="2" exponent="3" offset="0"/>
<feFuncB type="gamma" amplitude="2" exponent="1" offset="0"/>
</feComponentTransfer>
</filter>
</defs>
<rect fill="none" stroke="blue"
x="1" y="1" width="798" height="398"/>
<g font-family="Verdana" font-size="75"
font-weight="bold" fill="url(#MyGradient)" >
<rect x="100" y="0" width="600" height="20" />
<text x="100" y="90">Identity</text>
<text x="100" y="190" filter="url(#Table)" >TableLookup</text>
<text x="100" y="290" filter="url(#Linear)" >LinearFunc</text>
<text x="100" y="390" filter="url(#Gamma)" >GammaFunc</text>
</g>
</svg>![]() |
此滤镜使用 Porter-Duff [PORTERDUFF] 合成操作之一:over, in, atop, out, xor [SVG-COMPOSITING],在图像空间中对两个输入图像进行逐像素组合。此外,可以应用分量级的 arithmetic 操作(结果限制在 [0..1] 之间)。
arithmetic 操作对于将 ‘feDiffuseLighting’ 和 ‘feSpecularLighting’ 滤镜的输出与纹理数据组合非常有用。它对于实现 dissolve 也很有用。如果选择了 arithmetic 操作,则使用以下公式计算每个结果像素
result = k1*i1*i2 + k2*i1 + k3*i2 + k4其中
i1 和 i2 指示输入图像的对应像素通道值,它们分别映射到 in 和 in2k1, k2, k3 和 k4 表示同名属性的值对于此滤镜基元,结果图像的范围可能会如 滤镜基元子区域 一节所述增加。
属性定义
Example feComposite 展示了六种 feComposite 操作类型的示例。它还展示了两种在合成操作中使用 BackgroundImage 的不同技术。
前两行将蓝色的三角形渲染到背景中。应用了一个滤镜,使用其中一种合成操作将红色的三角形合成到蓝色三角形中。合成的结果被绘制到一个不透明的白色临时表面上,然后该结果被写入画布。(不透明的白色临时表面覆盖了原始的蓝色三角形。)
后两行应用了相同的将红色三角形合成到蓝色三角形中的合成操作。但是,合成结果直接混合到画布中(没有使用不透明的白色临时表面技术)。在某些情况下,结果与使用临时不透明白色表面的情况不同。背景中原始的蓝色三角形会在合成操作导致像素完全透明的地方透出来。在其他情况下,合成的结果与蓝色三角形混合,从而产生不同的最终颜色值。
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"https://w3org.cn/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="330" height="195" viewBox="0 0 1100 650" version="1.1"
xmlns="https://w3org.cn/2000/svg" xmlns:xlink="https://w3org.cn/1999/xlink">
<title>Example feComposite - Examples of feComposite operations</title>
<desc>Four rows of six pairs of overlapping triangles depicting
the six different feComposite operators under different
opacity values and different clearing of the background.</desc>
<defs>
<desc>Define two sets of six filters for each of the six compositing operators.
The first set wipes out the background image by flooding with opaque white.
The second set does not wipe out the background, with the result
that the background sometimes shines through and is other cases
is blended into itself (i.e., "double-counting").</desc>
<filter id="overFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feFlood flood-color="#ffffff" flood-opacity="1" result="flood"/>
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="over" result="comp"/>
<feMerge> <feMergeNode in="flood"/> <feMergeNode in="comp"/> </feMerge>
</filter>
<filter id="inFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feFlood flood-color="#ffffff" flood-opacity="1" result="flood"/>
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="in" result="comp"/>
<feMerge> <feMergeNode in="flood"/> <feMergeNode in="comp"/> </feMerge>
</filter>
<filter id="outFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feFlood flood-color="#ffffff" flood-opacity="1" result="flood"/>
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="out" result="comp"/>
<feMerge> <feMergeNode in="flood"/> <feMergeNode in="comp"/> </feMerge>
</filter>
<filter id="atopFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feFlood flood-color="#ffffff" flood-opacity="1" result="flood"/>
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="atop" result="comp"/>
<feMerge> <feMergeNode in="flood"/> <feMergeNode in="comp"/> </feMerge>
</filter>
<filter id="xorFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feFlood flood-color="#ffffff" flood-opacity="1" result="flood"/>
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="xor" result="comp"/>
<feMerge> <feMergeNode in="flood"/> <feMergeNode in="comp"/> </feMerge>
</filter>
<filter id="arithmeticFlood" filterUnits="objectBoundingBox"
x="-5%" y="-5%" width="110%" height="110%">
<feFlood flood-color="#ffffff" flood-opacity="1" result="flood"/>
<feComposite in="SourceGraphic" in2="BackgroundImage" result="comp"
operator="arithmetic" k1=".5" k2=".5" k3=".5" k4=".5"/>
<feMerge> <feMergeNode in="flood"/> <feMergeNode in="comp"/> </feMerge>
</filter>
<filter id="overNoFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="over" result="comp"/>
</filter>
<filter id="inNoFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="in" result="comp"/>
</filter>
<filter id="outNoFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="out" result="comp"/>
</filter>
<filter id="atopNoFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="atop" result="comp"/>
</filter>
<filter id="xorNoFlood" filterUnits="objectBoundingBox" x="-5%" y="-5%" width="110%" height="110%">
<feComposite in="SourceGraphic" in2="BackgroundImage" operator="xor" result="comp"/>
</filter>
<filter id="arithmeticNoFlood" filterUnits="objectBoundingBox"
x="-5%" y="-5%" width="110%" height="110%">
<feComposite in="SourceGraphic" in2="BackgroundImage" result="comp"
operator="arithmetic" k1=".5" k2=".5" k3=".5" k4=".5"/>
</filter>
<path id="Blue100" d="M 0 0 L 100 0 L 100 100 z" fill="#00ffff" />
<path id="Red100" d="M 0 0 L 0 100 L 100 0 z" fill="#ff00ff" />
<path id="Blue50" d="M 0 125 L 100 125 L 100 225 z" fill="#00ffff" fill-opacity=".5" />
<path id="Red50" d="M 0 125 L 0 225 L 100 125 z" fill="#ff00ff" fill-opacity=".5" />
<g id="TwoBlueTriangles">
<use xlink:href="#Blue100"/>
<use xlink:href="#Blue50"/>
</g>
<g id="BlueTriangles">
<use transform="translate(275,25)" xlink:href="#TwoBlueTriangles"/>
<use transform="translate(400,25)" xlink:href="#TwoBlueTriangles"/>
<use transform="translate(525,25)" xlink:href="#TwoBlueTriangles"/>
<use transform="translate(650,25)" xlink:href="#TwoBlueTriangles"/>
<use transform="translate(775,25)" xlink:href="#TwoBlueTriangles"/>
<use transform="translate(900,25)" xlink:href="#TwoBlueTriangles"/>
</g>
</defs>
<rect fill="none" stroke="blue" x="1" y="1" width="1098" height="648"/>
<g font-family="Verdana" font-size="40" shape-rendering="crispEdges">
<desc>Render the examples using the filters that draw on top of
an opaque white surface, thus obliterating the background.</desc>
<g enable-background="new">
<text x="15" y="75">opacity 1.0</text>
<text x="15" y="115" font-size="27">(with feFlood)</text>
<text x="15" y="200">opacity 0.5</text>
<text x="15" y="240" font-size="27">(with feFlood)</text>
<use xlink:href="#BlueTriangles"/>
<g transform="translate(275,25)">
<use xlink:href="#Red100" filter="url(#overFlood)" />
<use xlink:href="#Red50" filter="url(#overFlood)" />
<text x="5" y="275">over</text>
</g>
<g transform="translate(400,25)">
<use xlink:href="#Red100" filter="url(#inFlood)" />
<use xlink:href="#Red50" filter="url(#inFlood)" />
<text x="35" y="275">in</text>
</g>
<g transform="translate(525,25)">
<use xlink:href="#Red100" filter="url(#outFlood)" />
<use xlink:href="#Red50" filter="url(#outFlood)" />
<text x="15" y="275">out</text>
</g>
<g transform="translate(650,25)">
<use xlink:href="#Red100" filter="url(#atopFlood)" />
<use xlink:href="#Red50" filter="url(#atopFlood)" />
<text x="10" y="275">atop</text>
</g>
<g transform="translate(775,25)">
<use xlink:href="#Red100" filter="url(#xorFlood)" />
<use xlink:href="#Red50" filter="url(#xorFlood)" />
<text x="15" y="275">xor</text>
</g>
<g transform="translate(900,25)">
<use xlink:href="#Red100" filter="url(#arithmeticFlood)" />
<use xlink:href="#Red50" filter="url(#arithmeticFlood)" />
<text x="-25" y="275">arithmetic</text>
</g>
</g>
<g transform="translate(0,325)" enable-background="new">
<desc>Render the examples using the filters that do not obliterate
the background, thus sometimes causing the background to continue
to appear in some cases, and in other cases the background
image blends into itself ("double-counting").</desc>
<text x="15" y="75">opacity 1.0</text>
<text x="15" y="115" font-size="27">(without feFlood)</text>
<text x="15" y="200">opacity 0.5</text>
<text x="15" y="240" font-size="27">(without feFlood)</text>
<use xlink:href="#BlueTriangles"/>
<g transform="translate(275,25)">
<use xlink:href="#Red100" filter="url(#overNoFlood)" />
<use xlink:href="#Red50" filter="url(#overNoFlood)" />
<text x="5" y="275">over</text>
</g>
<g transform="translate(400,25)">
<use xlink:href="#Red100" filter="url(#inNoFlood)" />
<use xlink:href="#Red50" filter="url(#inNoFlood)" />
<text x="35" y="275">in</text>
</g>
<g transform="translate(525,25)">
<use xlink:href="#Red100" filter="url(#outNoFlood)" />
<use xlink:href="#Red50" filter="url(#outNoFlood)" />
<text x="15" y="275">out</text>
</g>
<g transform="translate(650,25)">
<use xlink:href="#Red100" filter="url(#atopNoFlood)" />
<use xlink:href="#Red50" filter="url(#atopNoFlood)" />
<text x="10" y="275">atop</text>
</g>
<g transform="translate(775,25)">
<use xlink:href="#Red100" filter="url(#xorNoFlood)" />
<use xlink:href="#Red50" filter="url(#xorNoFlood)" />
<text x="15" y="275">xor</text>
</g>
<g transform="translate(900,25)">
<use xlink:href="#Red100" filter="url(#arithmeticNoFlood)" />
<use xlink:href="#Red50" filter="url(#arithmeticNoFlood)" />
<text x="-25" y="275">arithmetic</text>
</g>
</g>
</g>
</svg>![]() |
feConvolveMatrix 应用矩阵卷积滤镜效果。卷积将输入图像中的像素与其相邻像素组合,从而产生结果图像。通过卷积可以实现多种图像操作,包括模糊、边缘检测、锐化、浮雕和斜角效果。
矩阵卷积基于 n x m 矩阵(卷积核),该矩阵描述了输入图像中给定像素值如何与其相邻像素值组合以产生结果像素值。每个结果像素通过将核矩阵应用于相应的源像素及其相邻像素来确定。应用于给定像素的每个颜色值的基本卷积公式为
COLORX,Y = (
SUM I=0 to [orderY-1] {
SUM J=0 to [orderX-1] {
SOURCE X-targetX+J, Y-targetY+I * kernelMatrixorderX-J-1, orderY-I-1
}
}
) / divisor + bias * ALPHAX,Y
其中 "orderX" 和 "orderY" 表示 ‘order’ 属性的 X 和 Y 值,"targetX" 表示 ‘targetX’ 属性的值,"targetY" 表示 ‘targetY’ 属性的值,"kernelMatrix" 表示 ‘kernelMatrix’ 属性的值,"divisor" 表示 ‘divisor’ 属性的值,"bias" 表示 ‘bias’ 属性的值。
请注意上述公式中,内核矩阵中的值应用时,内核矩阵相对于源图像和目标图像旋转了 180 度,以便与许多计算机图形学教科书中描述的卷积理论相匹配。
举例来说,假设你有一个 5 x 5 像素的输入图像,其中一个颜色通道的颜色值如下所示
0 20 40 235 235 100 120 140 235 235 200 220 240 235 235 225 225 255 255 255 225 225 255 255 255
并且你定义了一个 3 x 3 的卷积核如下
1 2 3 4 5 6 7 8 9
让我们聚焦于图像第二行第二列的颜色值(源像素值为 120)。假设最简单的情况(输入图像的像素网格与内核的像素网格完全对齐)并假设属性 ‘divisor’、‘targetX’ 和 ‘targetY’ 为默认值,则产生的颜色值为
(9* 0 + 8* 20 + 7* 40 + 6*100 + 5*120 + 4*140 + 3*200 + 2*220 + 1*240) / (9+8+7+6+5+4+3+2+1)
由于它们在像素上操作,矩阵卷积本质上是依赖于分辨率的。为了使 ‘feConvolveMatrix’ 产生独立于分辨率的结果,应该为 ‘filter’ 元素上的 ‘filterRes’ 属性和/或 ‘kernelUnitLength’ 属性提供明确的值。
‘kernelUnitLength’ 与其他属性结合,定义了滤镜效果坐标系(即由 ‘primitiveUnits’ 属性建立的坐标系)中的隐含像素网格。如果由 ‘kernelUnitLength’ 建立的像素网格没有缩放以匹配由 ‘filterRes’ 属性(隐式或显式)建立的像素网格,那么输入图像将被临时重新缩放,使其像素与 ‘kernelUnitLength’ 相匹配。卷积在重采样后的图像上进行。应用卷积后,图像被重采样回原始分辨率。
当图像必须在卷积前重采样以匹配 ‘kernelUnitLength’ 定义的坐标系,或在卷积后重采样以匹配设备坐标系时,建议 高质量查看器 使用适当的插值技术,例如双线性或双三次插值。根据可用插值器的速度,此选择可能会受到 ‘image-rendering’ 属性设置的影响。请注意,实现可能会选择在不需要时最小化或消除重采样的方案,例如当文档缩小时,‘kernelUnitLength’ 远小于一个设备像素。
属性定义
确定如何在必要时使用颜色值扩展输入图像,以便在核定位在输入图像边缘或附近时应用矩阵运算。
"duplicate" 表示输入图像根据需要沿着其每个边界进行扩展,方法是复制输入图像给定边缘的颜色值。
Original N-by-M image, where m=M-1 and n=N-1:
11 12 ... 1m 1M
21 22 ... 2m 2M
.. .. ... .. ..
n1 n2 ... nm nM
N1 N2 ... Nm NM
Extended by two pixels using "duplicate":
11 11 11 12 ... 1m 1M 1M 1M
11 11 11 12 ... 1m 1M 1M 1M
11 11 11 12 ... 1m 1M 1M 1M
21 21 21 22 ... 2m 2M 2M 2M
.. .. .. .. ... .. .. .. ..
n1 n1 n1 n2 ... nm nM nM nM
N1 N1 N1 N2 ... Nm NM NM NM
N1 N1 N1 N2 ... Nm NM NM NM
N1 N1 N1 N2 ... Nm NM NM NM
"wrap" 表示通过从图像的相对边缘获取颜色值来扩展输入图像。
Extended by two pixels using "wrap": nm nM n1 n2 ... nm nM n1 n2 Nm NM N1 N2 ... Nm NM N1 N2 1m 1M 11 12 ... 1m 1M 11 12 2m 2M 21 22 ... 2m 2M 21 22 .. .. .. .. ... .. .. .. .. nm nM n1 n2 ... nm nM n1 n2 Nm NM N1 N2 ... Nm NM N1 N2 1m 1M 11 12 ... 1m 1M 11 12 2m 2M 21 22 ... 2m 2M 21 22
"none" 表示输入图像使用 R、G、B 和 A 的零像素值进行扩展。
如果未指定属性 ‘edgeMode’,则其效果如同指定了值 duplicate 一样。
可动画:是。
ALPHAX,Y 为ALPHAX,Y = (
SUM I=0 to [orderY-1] {
SUM J=0 to [orderX-1] {
SOURCE X-targetX+J, Y-targetY+I * kernelMatrixorderX-J-1, orderY-I-1
}
}
) / divisor + bias
ALPHAX,Y 为ALPHAX,Y = SOURCEX,Y
此滤镜原始操作使用 Alpha 通道作为凹凸贴图对图像进行光照处理。生成的图像是一个 RGBA 不透明图像,基于光照颜色,且各处的 alpha = 1.0。光照计算遵循 Phong 光照模型的标准漫反射分量。结果图像取决于光照颜色、光照位置以及输入凹凸贴图的表面几何结构。
此滤镜原语生成的光照图可以使用算术 ‘feComposite’ 合成方法的乘法项与纹理图像组合。在将其应用于纹理图像之前,可以通过将多个此类光照图相加来模拟多个光源。
以下公式使用 3x3 滤镜。因为它们在像素上操作,所以此类滤镜本质上是依赖于分辨率的。为了使 ‘feDiffuseLighting’ 产生独立于分辨率的结果,应该为 ‘filter’ 元素上的 ‘filterRes’ 属性和/或 ‘kernelUnitLength’ 属性提供明确的值。
‘kernelUnitLength’ 与其他属性结合,定义了滤镜效果坐标系(即由 ‘primitiveUnits’ 属性建立的坐标系)中的隐含像素网格。如果由 ‘kernelUnitLength’ 建立的像素网格没有缩放以匹配由 ‘filterRes’ 属性(隐式或显式)建立的像素网格,那么输入图像将被临时重新缩放,使其像素与 ‘kernelUnitLength’ 相匹配。3x3 滤镜应用于重采样后的图像。应用滤镜后,图像被重采样回其原始分辨率。
当必须重采样图像时,建议 高质量查看器 使用适当的插值技术,例如双线性或双三次插值。根据可用插值器的速度,此选择可能会受到 ‘image-rendering’ 属性设置的影响。请注意,实现可能会选择在不需要时最小化或消除重采样的方案,例如当文档缩小时,‘kernelUnitLength’ 远小于一个设备像素。
对于随后的公式,Norm(Ax,Ay,Az) 函数定义为
Norm(Ax,Ay,Az) = sqrt(Ax^2+Ay^2+Az^2)
最终的 RGBA 图像计算如下
Dr = kd * N.L * Lr
Dg = kd * N.L * Lg
Db = kd * N.L * Lb
Da = 1.0
其中
N 是 x 和 y 的函数,取决于表面梯度,如下所示
输入 alpha 图像 I(x,y) 所描述的表面为
Z (x,y) = surfaceScale * I(x,y)
表面法线是使用 Sobel 梯度 3x3 滤镜计算的。根据给定的像素是在内部还是边缘,使用不同的滤镜核。对于每种情况,公式为
Nx (x,y)= - surfaceScale * FACTORx *
(Kx(0,0)*I(x-dx,y-dy) + Kx(1,0)*I(x,y-dy) + Kx(2,0)*I(x+dx,y-dy) +
Kx(0,1)*I(x-dx,y) + Kx(1,1)*I(x,y) + Kx(2,1)*I(x+dx,y) +
Kx(0,2)*I(x-dx,y+dy) + Kx(1,2)*I(x,y+dy) + Kx(2,2)*I(x+dx,y+dy))
Ny (x,y)= - surfaceScale * FACTORy *
(Ky(0,0)*I(x-dx,y-dy) + Ky(1,0)*I(x,y-dy) + Ky(2,0)*I(x+dx,y-dy) +
Ky(0,1)*I(x-dx,y) + Ky(1,1)*I(x,y) + Ky(2,1)*I(x+dx,y) +
Ky(0,2)*I(x-dx,y+dy) + Ky(1,2)*I(x,y+dy) + Ky(2,2)*I(x+dx,y+dy))
Nz (x,y) = 1.0
N = (Nx, Ny, Nz) / Norm((Nx,Ny,Nz))
在这些公式中,dx 和 dy 值(例如 I(x-dx,y-dy))表示相对于给定 (x,y) 位置的增量,目的是估计该点表面的斜率。这些增量由 ‘kernelUnitLength’ 属性的值(显式或隐式)决定。
|
左上角 FACTORx=2/(3*dx) |
顶行 FACTORx=1/(3*dx) |
右上角 FACTORx=2/(3*dx) |
|
左列 FACTORx=1/(2*dx) |
内部像素 FACTORx=1/(4*dx) |
右列 FACTORx=1/(2*dx) |
|
左下角 FACTORx=2/(3*dx) |
底行 FACTORx=1/(3*dx) |
右下角 FACTORx=2/(3*dx) |
L,从图像样本到光源的单位向量,计算如下
对于无限光源,它是恒定的
Lx = cos(azimuth)*cos(elevation)
Ly = sin(azimuth)*cos(elevation)
Lz = sin(elevation)
对于点光源和聚光灯,它是位置的函数
Lx = Lightx - x
Ly = Lighty - y
Lz = Lightz - Z(x,y)
L = (Lx, Ly, Lz) / Norm(Lx, Ly, Lz)
其中 Lightx, Lighty, Lightz 是输入的光源位置。
Lr,Lg,Lb,光照颜色向量,仅在聚光灯情况下是位置的函数
Lr = Lightr*pow((-L.S),specularExponent)
Lg = Lightg*pow((-L.S),specularExponent)
Lb = Lightb*pow((-L.S),specularExponent)
其中 S 是从光源指向 x-y 平面上点 (pointsAtX, pointsAtY, pointsAtZ) 的单位向量
Sx = pointsAtX - Lightx
Sy = pointsAtY - Lighty
Sz = pointsAtZ - Lightz
S = (Sx, Sy, Sz) / Norm(Sx, Sy, Sz)
如果 L.S 为正,则没有光存在。(Lr = Lg = Lb = 0)。如果指定了 ‘limitingConeAngle’,-L.S < cos(limitingConeAngle) 也表示没有光存在。
属性定义
dx 和 dy 的预期距离(单位为当前滤镜单位,即由 ‘primitiveUnits’ 属性决定的单位)。通过为 ‘kernelUnitLength’ 指定值,内核在可缩放的抽象坐标系中定义。如果未指定 ‘kernelUnitLength’,dx 和 dy 值应表示相对于给定 (x,y) 位置的非常小的增量,在某些情况下实现为中间图像屏幕外位图中的一个像素,这是一个基于像素的坐标系,因此可能不可缩放。为了在显示媒体和用户代理之间保持某种程度的一致性,必须为 ‘filterRes’ 和 ‘kernelUnitLength’ 中的至少一个提供值。关于中间图像的讨论在 介绍 中以及属性 ‘filterRes’ 的描述中。光源由子元素 ‘feDistantLight’、‘fePointLight’ 或 ‘feSpotLight’ 之一定义。光照颜色由属性 ‘lighting-color’ 指定。
此滤镜原语使用来自 ‘in2’ 的图像像素值来对来自 ‘in’ 的图像进行空间位移。这是要执行的转换
P'(x,y) <- P( x + scale * (XC(x,y) - .5), y + scale * (YC(x,y) - .5))
其中 P(x,y) 是输入图像 ‘in’,P'(x,y) 是目标。XC(x,y) 和 YC(x,y) 是由 xChannelSelector 和 yChannelSelector 指定的通道的分量值。例如,要使用 ‘in2’ 的 R 分量来控制 x 方向的位移,并使用 Image2 的 G 分量来控制 y 方向的位移,请将 xChannelSelector 设置为 "R",将 yChannelSelector 设置为 "G"。
位移图定义了所执行映射的逆映射。
输入图像 in 对于此滤镜原语必须保持预乘状态。使用来自 ‘in2’ 的像素值的计算使用非预乘颜色值执行。如果来自 ‘in2’ 的图像包含预乘颜色值,则这些值在执行此操作之前会自动转换为非预乘颜色值。
此滤镜可能对输入产生任意的非局部影响,这可能需要在处理流水线中进行大量的缓冲。然而,通过这种公式,任何中间缓冲需求都可以由 scale 确定,它表示 x 或 y 方向上的最大位移范围。
应用此滤镜时,源像素位置通常位于多个源像素之间。在这种情况下,建议 高质量查看器 对周围像素应用插值,例如双线性或双三次插值,而不是简单地选择最近的源像素。根据可用插值器的速度,此选择可能会受到 ‘image-rendering’ 属性设置的影响。
‘color-interpolation-filters’ 属性仅适用于 ‘in2’ 源图像,不适用于 ‘in’ 源图像。‘in’ 源图像必须保持在其当前的颜色空间中。
属性定义
此滤镜原语创建一个矩形,填充来自属性 ‘flood-color’ 和 ‘flood-opacity’ 的颜色和不透明度值。该矩形的大小与由 ‘feFlood’ 元素上的 ‘x’、‘y’、‘width’ 和 ‘height’ 属性建立的 滤镜原语子区域 一样大。
‘flood-color’ 属性指示使用什么颜色来填充当前的 滤镜原语子区域。关键字 currentColor 和 ICC 颜色可以按照与 ‘fill’ 和 ‘stroke’ 属性的 <paint> 规范相同的方式指定。
| 值 | currentColor | <color> [<icccolor>] | inherit |
| 初始值 | black (黑色) |
| 应用于 | ‘feFlood’ 元素 |
| 可继承 | 否 |
| 百分比 | 不适用 |
| 媒体 | 视觉 |
| 可动画: | 是 |
‘flood-opacity’ 属性定义在整个 滤镜原语子区域 中使用的不透明度值。
此滤镜原始操作对输入图像执行高斯模糊。
高斯模糊核是归一化卷积的近似
G(x,y) = H(x)I(y)
其中
H(x) = exp(-x2/ (2s2)) / sqrt(2* pi*s2)
以及
I(y) = exp(-y2/ (2t2)) / sqrt(2* pi*t2)
其中 's' 是 x 方向的标准差,'t' 是 y 方向的标准差,由 ‘stdDeviation’ 指定。
‘stdDeviation’ 的值可以是一个或两个数字。如果提供两个数字,第一个数字表示当前坐标系沿 x 轴的标准差值,第二个值表示 Y 轴的标准差。如果提供一个数字,则该值同时用于 X 和 Y。
即使仅为 ‘stdDeviation’ 提供一个值,也可以实现为可分离卷积。
对于较大的 's' 值(s >= 2.0),可以使用一种近似值:三次连续的方框模糊构建了一个分段二次卷积核,它对高斯核的近似误差在 3% 以内。
let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
... 如果 d 是奇数,使用三个尺寸为 'd' 的方框模糊,以输出像素为中心。
... 如果 d 是偶数,使用两个尺寸为 'd' 的方框模糊(第一个以输出像素和左侧像素之间的像素边界为中心,第二个以输出像素和右侧像素之间的像素边界为中心)以及一个以输出像素为中心的尺寸为 'd+1' 的方框模糊。
注意:近似公式也相应地适用于 't'。
此操作通常会在仅有 Alpha 的图像上进行,例如由内置输入 SourceAlpha 产生的图像。实现可能会注意到这一点并优化单通道情况。如果输入具有无限范围并且是恒定的(例如 FillPaint,其中填充是纯色),则此操作没有效果。如果输入具有无限范围,并且滤镜结果是 ‘feTile’ 的输入,则滤镜将使用周期性边界条件进行评估。
属性定义
本章开头的示例利用 ‘feGaussianBlur’ 滤镜原语来创建投影效果。
此滤镜基元引用该滤镜元素外部的图形,将其加载或渲染为 RGBA 光栅并成为滤镜基元的结果。
此滤镜原语可以引用外部图像,也可以是对 SVG 其他部分的引用。它产生类似于内置图像源 SourceGraphic 的图像,只是图形来自外部源。
如果 ‘xlink:href’ 引用了独立的图像资源(如 JPEG、PNG 或 SVG 文件),则图像资源将根据 ‘image’ 元素的操作进行渲染;否则,引用的资源将根据 ‘use’ 元素的操作进行渲染。在任何情况下,当前用户坐标系都取决于 ‘filter’ 元素上 ‘primitiveUnits’ 属性的值。‘feImage’ 元素上 ‘preserveAspectRatio’ 属性的处理与 ‘image’ 元素的处理相同。
当引用的图像必须重采样以匹配设备坐标系时,建议 高质量查看器 使用适当的插值技术,例如双线性或双三次插值。根据可用插值器的速度,此选择可能会受到 ‘image-rendering’ 属性设置的影响。
属性定义
对图像源的 IRI 引用。
可动画:是。
如果未指定属性 ‘preserveAspectRatio’,则其效果如同指定了值 xMidYMid meet 一样。
可动画:是。
Example feImage 展示了如何将图像相对于对象进行放置。从左到右
<svg width="600" height="250" viewBox="0 0 600 250"
xmlns="https://w3org.cn/2000/svg"
xmlns:xlink="https://w3org.cn/1999/xlink">
<title>Example feImage - Examples of feImage use</title>
<desc>Three examples of using feImage, the first showing the
default rendering, the second showing the image fit
to a box and the third showing the image
shifted and clipped.</desc>
<defs>
<filter id="Default">
<feImage xlink:href="smiley.png" />
</filter>
<filter id="Fitted" primitiveUnits="objectBoundingBox">
<feImage xlink:href="smiley.png"
x="0" y="0" width="100%" height="100%"
preserveAspectRatio="none"/>
</filter>
<filter id="Shifted">
<feImage xlink:href="smiley.png"
x="500" y="5"/>
</filter>
</defs>
<rect fill="none" stroke="blue"
x="1" y="1" width="598" height="248"/>
<g>
<rect x="50" y="25" width="100" height="200" filter="url(#Default)"/>
<rect x="50" y="25" width="100" height="200" fill="none" stroke="green"/>
<rect x="250" y="25" width="100" height="200" filter="url(#Fitted)"/>
<rect x="250" y="25" width="100" height="200" fill="none" stroke="green"/>
<rect x="450" y="25" width="100" height="200" filter="url(#Shifted)"/>
<rect x="450" y="25" width="100" height="200" fill="none" stroke="green"/>
</g>
</svg>![]() |
此滤镜原语使用 over 运算符将输入图像层堆叠在一起,其中 Input1(对应于第一个 ‘feMergeNode’ 子元素)在底部,最后指定的输入 InputN(对应于最后一个 ‘feMergeNode’ 子元素)在顶部。
许多效果会产生多个中间层以创建最终输出图像。此滤镜允许我们将这些层合并为单个图像。尽管可以使用 n-1 个合成滤镜完成此操作,但以这种形式提供此常用操作更为方便,并为实现提供了额外的灵活性。
每个 ‘feMerge’ 元素可以有任意数量的 ‘feMergeNode’ 子元素,每个子元素都有一个 ‘in’ 属性。
feMerge 的典型实现是将整个效果渲染为一个 RGBA 层,然后将结果层渲染到输出设备上。在某些情况下(特别是如果输出设备本身是连续色调设备),并且由于合并具有关联性,将效果逐层评估并将每一层从下到上依次渲染到输出设备上可能是一个足够好的近似。
如果最顶层的图像输入是 SourceGraphic 且此 ‘feMerge’ 是滤镜中的最后一个滤镜原语,则鼓励实现将图层渲染到该点,然后将 SourceGraphic 直接从其矢量描述渲染在顶部。
本章开头的示例利用 ‘feMerge’ 滤镜原语将两个中间滤镜结果合在一起。
此滤镜基元执行艺术品的“加粗”或“变细”操作。这对于加粗或变细 alpha 通道特别有用。
膨胀(或腐蚀)核是一个宽度为 2*x-radius、高度为 2*y-radius 的矩形。在膨胀中,输出像素是输入图像核矩形中相应 R、G、B、A 值的各个分量的最大值。在腐蚀中,输出像素是输入图像核矩形中相应 R、G、B、A 值的各个分量的最小值。
此操作通常会在仅有 Alpha 的图像上进行,例如由内置输入 SourceAlpha 产生的图像。在这种情况下,实现可能希望优化单通道情况。
如果输入具有无限范围并且是恒定的(例如 FillPaint,其中填充是纯色),则此操作没有效果。如果输入具有无限范围,并且滤镜结果是 ‘feTile’ 的输入,则滤镜将使用周期性边界条件进行评估。
因为 ‘feMorphology’ 在预乘颜色值上操作,它总是会导致颜色值小于或等于 Alpha 通道。
属性定义
Example feMorphology 展示了四种 feMorphology 操作类型的示例。
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"https://w3org.cn/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="5cm" height="7cm" viewBox="0 0 700 500"
xmlns="https://w3org.cn/2000/svg" version="1.1">
<title>Example feMorphology - Examples of erode and dilate</title>
<desc>Five text strings drawn as outlines.
The first is unfiltered. The second and third use 'erode'.
The fourth and fifth use 'dilate'.</desc>
<defs>
<filter id="Erode3">
<feMorphology operator="erode" in="SourceGraphic" radius="3" />
</filter>
<filter id="Erode6">
<feMorphology operator="erode" in="SourceGraphic" radius="6" />
</filter>
<filter id="Dilate3">
<feMorphology operator="dilate" in="SourceGraphic" radius="3" />
</filter>
<filter id="Dilate6">
<feMorphology operator="dilate" in="SourceGraphic" radius="6" />
</filter>
</defs>
<rect fill="none" stroke="blue" stroke-width="2"
x="1" y="1" width="698" height="498"/>
<g enable-background="new" >
<g font-family="Verdana" font-size="75"
fill="none" stroke="black" stroke-width="6" >
<text x="50" y="90">Unfiltered</text>
<text x="50" y="180" filter="url(#Erode3)" >Erode radius 3</text>
<text x="50" y="270" filter="url(#Erode6)" >Erode radius 6</text>
<text x="50" y="360" filter="url(#Dilate3)" >Dilate radius 3</text>
<text x="50" y="450" filter="url(#Dilate6)" >Dilate radius 6</text>
</g>
</g>
</svg>![]() |
此滤镜基元将输入图像相对于其在图像空间中的当前位置偏移指定的向量。
这对于投影等效果非常重要。
应用此滤镜时,目标位置在设备空间中可能会偏移像素的一小部分。在这种情况下,高质量查看器 应使用适当的插值技术,例如双线性或双三次插值。这特别推荐用于动态查看器,因为这种插值提供了视觉上更平滑的图像移动。对于静态查看器,这不太受关注。应密切关注 ‘image-rendering’ 属性设置,以确定作者的意图。
属性定义
本章开头的示例利用 ‘feOffset’ 滤镜原语将投影从原始源图形中偏移出来。
此滤镜原语使用 Alpha 通道作为凹凸贴图来照亮源图形。生成的图像是基于光照颜色的 RGBA 图像。光照计算遵循 Phong 光照模型的标准镜面反射分量。生成的图像取决于输入凹凸贴图的灯光颜色、灯光位置和表面几何形状。光照计算的结果被相加。滤镜原语假设查看者位于 z 方向的无穷远处(即视线方向上的单位向量在任何地方都是 (0,0,1))。
此滤镜原语生成一个包含光照计算中镜面反射部分的图像。这样的贴图旨在通过 arithmetic ‘feComposite’ 方法的 add 项与纹理组合。多个光源可以通过在将其应用于纹理图像之前相加多个此类光照图来模拟。
最终的 RGBA 图像计算如下
Sr = ks * pow(N.H, specularExponent) * Lr
Sg = ks * pow(N.H, specularExponent) * Lg
Sb = ks * pow(N.H, specularExponent) * Lb
Sa = max(Sr, Sg, Sb)
其中
有关 N 和 (Lr, Lg, Lb) 的定义,请参见 ‘feDiffuseLighting’。
H 的定义反映了我们对恒定视线向量 E = (0,0,1) 的假设
H = (L + E) / Norm(L+E)
其中 L 是光线单位向量。
与 ‘feDiffuseLighting’ 不同,‘feSpecularLighting’ 滤镜产生的图像是非不透明的。这是因为镜面反射结果 (Sr,Sg,Sb,Sa) 旨在添加到纹理图像中。结果的 Alpha 通道是颜色分量的最大值,因此在镜面光为零的地方,图像不会增加额外的覆盖范围,而纯白色的高光会增加不透明度。
‘feDiffuseLighting’ 和 ‘feSpecularLighting’ 滤镜通常会一起应用。实现可能会检测到这一点并一次性计算两张贴图,而不是两次。
属性定义
dx 和 dy 的预期距离(单位为当前滤镜单位,即由 ‘primitiveUnits’ 属性决定的单位)。通过为 ‘kernelUnitLength’ 指定值,内核在可缩放的抽象坐标系中定义。如果未指定 ‘kernelUnitLength’,dx 和 dy 值应表示相对于给定 (x,y) 位置的非常小的增量,在某些情况下实现为中间图像屏幕外位图中的一个像素,这是一个基于像素的坐标系,因此可能不可缩放。为了在显示媒体和用户代理之间保持某种程度的一致性,必须为 ‘filterRes’ 和 ‘kernelUnitLength’ 中的至少一个提供值。关于中间图像的讨论在 介绍 中以及属性 ‘filterRes’ 的描述中。光源由子元素 ‘feDistantLight’、‘fePointLight’ 或 ‘feDistantLight’ 之一定义。光照颜色由属性 ‘lighting-color’ 指定。
本章开头的示例利用 ‘feSpecularLighting’ 滤镜原语来实现高反射、3D 发光效果。
此滤镜原语用输入图像的重复平铺图案填充目标矩形。该矩形的大小与由 ‘feTile’ 元素上的 ‘x’、‘y’、‘width’ 和 ‘height’ 属性建立的 滤镜原语子区域 一样大。
通常,输入图像已定义了自己的 滤镜原语子区域,以便定义参考平铺。‘feTile’ 在 X 和 Y 方向上复制参考平铺,以完全填充目标矩形。每个给定平铺的左上角位于 (x+i*width,y+j*height),其中 (x,y) 表示输入图像滤镜原语子区域的左上角,width 和 height 表示输入图像滤镜原语子区域的宽度和高度,i 和 j 可以是任何整数值。在大多数情况下,为了达到重复图案的效果,输入图像将具有比 ‘feTile’ 更小的 滤镜原语子区域。
实现者在构建平铺图像时必须采取适当措施,以避免图块之间出现伪影,特别是在用户到设备的变换包含错切(shear)和/或旋转的情况下。如果不加以注意,由于相邻图块的绘制与特定像素有部分重叠,插值可能会导致图块边缘像素的不透明度值低于或高于预期。
此滤镜原语使用柏林(Perlin)湍流函数创建图像。它允许合成云或大理石等人工纹理。关于柏林湍流函数的详细描述,请参阅 "Texturing and Modeling", Ebert 等人, AP Professional, 1994。生成的图像将填满此滤镜原语的整个 滤镜原语子区域。
可以通过仅合成一个倍频程(octave)来创建带宽受限的噪声。
下面的 C 代码展示了此滤镜效果所使用的精确算法。
对于 fractalSum,你得到的 turbFunctionResult 范围为 -1 到 1(实际结果在某些情况下可能会超出此范围)。要转换为颜色值,请使用公式 colorValue = ((turbFunctionResult * 255) + 255) / 2,然后将其截断到 0 到 255 的范围内。
对于 turbulence,你得到的 turbFunctionResult 范围为 0 到 1(实际结果在某些情况下可能会超出此范围)。要转换为颜色值,请使用公式 colorValue = (turbFunctionResult * 255),然后将其截断到 0 到 255 的范围内。
以下顺序用于应用伪随机数。初始种子值是根据属性 ‘seed’ 计算的。然后实现为 R 计算晶格点,然后继续获取相对于上一个生成的伪随机数的附加伪随机数并为 G 计算晶格点,依此类推,直到 B 和 A。
生成的颜色和 Alpha 值位于由属性 ‘color-interpolation-filters’ 的值确定的颜色空间中。
/* Produces results in the range [1, 2**31 - 2].
Algorithm is: r = (a * r) mod m
where a = 16807 and m = 2**31 - 1 = 2147483647
See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
To test: the algorithm should produce the result 1043618065
as the 10,000th generated number if the original seed is 1.
*/
#define RAND_m 2147483647 /* 2**31 - 1 */
#define RAND_a 16807 /* 7**5; primitive root of m */
#define RAND_q 127773 /* m / a */
#define RAND_r 2836 /* m % a */
long setup_seed(long lSeed)
{
if (lSeed <= 0) lSeed = -(lSeed % (RAND_m - 1)) + 1;
if (lSeed > RAND_m - 1) lSeed = RAND_m - 1;
return lSeed;
}
long random(long lSeed)
{
long result;
result = RAND_a * (lSeed % RAND_q) - RAND_r * (lSeed / RAND_q);
if (result <= 0) result += RAND_m;
return result;
}
#define BSize 0x100
#define BM 0xff
#define PerlinN 0x1000
#define NP 12 /* 2^PerlinN */
#define NM 0xfff
static uLatticeSelector[BSize + BSize + 2];
static double fGradient[4][BSize + BSize + 2][2];
struct StitchInfo
{
int nWidth; // How much to subtract to wrap for stitching.
int nHeight;
int nWrapX; // Minimum value to wrap.
int nWrapY;
};
static void init(long lSeed)
{
double s;
int i, j, k;
lSeed = setup_seed(lSeed);
for(k = 0; k < 4; k++)
{
for(i = 0; i < BSize; i++)
{
uLatticeSelector[i] = i;
for (j = 0; j < 2; j++)
fGradient[k][i][j] = (double)(((lSeed = random(lSeed)) % (BSize + BSize)) - BSize) / BSize;
s = double(sqrt(fGradient[k][i][0] * fGradient[k][i][0] + fGradient[k][i][1] * fGradient[k][i][1]));
fGradient[k][i][0] /= s;
fGradient[k][i][1] /= s;
}
}
while(--i)
{
k = uLatticeSelector[i];
uLatticeSelector[i] = uLatticeSelector[j = (lSeed = random(lSeed)) % BSize];
uLatticeSelector[j] = k;
}
for(i = 0; i < BSize + 2; i++)
{
uLatticeSelector[BSize + i] = uLatticeSelector[i];
for(k = 0; k < 4; k++)
for(j = 0; j < 2; j++)
fGradient[k][BSize + i][j] = fGradient[k][i][j];
}
}
#define s_curve(t) ( t * t * (3. - 2. * t) )
#define lerp(t, a, b) ( a + t * (b - a) )
double noise2(int nColorChannel, double vec[2], StitchInfo *pStitchInfo)
{
int bx0, bx1, by0, by1, b00, b10, b01, b11;
double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
register i, j;
t = vec[0] + PerlinN;
bx0 = (int)t;
bx1 = bx0+1;
rx0 = t - (int)t;
rx1 = rx0 - 1.0f;
t = vec[1] + PerlinN;
by0 = (int)t;
by1 = by0+1;
ry0 = t - (int)t;
ry1 = ry0 - 1.0f;
// If stitching, adjust lattice points accordingly.
if(pStitchInfo != NULL)
{
if(bx0 >= pStitchInfo->nWrapX)
bx0 -= pStitchInfo->nWidth;
if(bx1 >= pStitchInfo->nWrapX)
bx1 -= pStitchInfo->nWidth;
if(by0 >= pStitchInfo->nWrapY)
by0 -= pStitchInfo->nHeight;
if(by1 >= pStitchInfo->nWrapY)
by1 -= pStitchInfo->nHeight;
}
bx0 &= BM;
bx1 &= BM;
by0 &= BM;
by1 &= BM;
i = uLatticeSelector[bx0];
j = uLatticeSelector[bx1];
b00 = uLatticeSelector[i + by0];
b10 = uLatticeSelector[j + by0];
b01 = uLatticeSelector[i + by1];
b11 = uLatticeSelector[j + by1];
sx = double(s_curve(rx0));
sy = double(s_curve(ry0));
q = fGradient[nColorChannel][b00]; u = rx0 * q[0] + ry0 * q[1];
q = fGradient[nColorChannel][b10]; v = rx1 * q[0] + ry0 * q[1];
a = lerp(sx, u, v);
q = fGradient[nColorChannel][b01]; u = rx0 * q[0] + ry1 * q[1];
q = fGradient[nColorChannel][b11]; v = rx1 * q[0] + ry1 * q[1];
b = lerp(sx, u, v);
return lerp(sy, a, b);
}
double turbulence(int nColorChannel, double *point, double fBaseFreqX, double fBaseFreqY,
int nNumOctaves, bool bFractalSum, bool bDoStitching,
double fTileX, double fTileY, double fTileWidth, double fTileHeight)
{
StitchInfo stitch;
StitchInfo *pStitchInfo = NULL; // Not stitching when NULL.
// Adjust the base frequencies if necessary for stitching.
if(bDoStitching)
{
// When stitching tiled turbulence, the frequencies must be adjusted
// so that the tile borders will be continuous.
if(fBaseFreqX != 0.0)
{
double fLoFreq = double(floor(fTileWidth * fBaseFreqX)) / fTileWidth;
double fHiFreq = double(ceil(fTileWidth * fBaseFreqX)) / fTileWidth;
if(fBaseFreqX / fLoFreq < fHiFreq / fBaseFreqX)
fBaseFreqX = fLoFreq;
else
fBaseFreqX = fHiFreq;
}
if(fBaseFreqY != 0.0)
{
double fLoFreq = double(floor(fTileHeight * fBaseFreqY)) / fTileHeight;
double fHiFreq = double(ceil(fTileHeight * fBaseFreqY)) / fTileHeight;
if(fBaseFreqY / fLoFreq < fHiFreq / fBaseFreqY)
fBaseFreqY = fLoFreq;
else
fBaseFreqY = fHiFreq;
}
// Set up initial stitch values.
pStitchInfo = &stitch;
stitch.nWidth = int(fTileWidth * fBaseFreqX + 0.5f);
stitch.nWrapX = fTileX * fBaseFreqX + PerlinN + stitch.nWidth;
stitch.nHeight = int(fTileHeight * fBaseFreqY + 0.5f);
stitch.nWrapY = fTileY * fBaseFreqY + PerlinN + stitch.nHeight;
}
double fSum = 0.0f;
double vec[2];
vec[0] = point[0] * fBaseFreqX;
vec[1] = point[1] * fBaseFreqY;
double ratio = 1;
for(int nOctave = 0; nOctave < nNumOctaves; nOctave++)
{
if(bFractalSum)
fSum += double(noise2(nColorChannel, vec, pStitchInfo) / ratio);
else
fSum += double(fabs(noise2(nColorChannel, vec, pStitchInfo)) / ratio);
vec[0] *= 2;
vec[1] *= 2;
ratio *= 2;
if(pStitchInfo != NULL)
{
// Update stitch values. Subtracting PerlinN before the multiplication and
// adding it afterward simplifies to subtracting it once.
stitch.nWidth *= 2;
stitch.nWrapX = 2 * stitch.nWrapX - PerlinN;
stitch.nHeight *= 2;
stitch.nWrapY = 2 * stitch.nWrapY - PerlinN;
}
}
return fSum;
}
属性定义
lowFreq=floor(width*frequency)/width 和 hiFreq=ceil(width*frequency)/width。如果 frequency/lowFreq < hiFreq/frequency,则使用 lowFreq,否则使用 hiFreq。在生成湍流值时,为柏林噪声正常生成晶格向量,但位于活动区域(生成的平铺尺寸)右边缘或底边缘的晶格点除外。在这些情况下,从活动区域的相对边缘复制晶格向量。如果未指定属性 ‘stitchTiles’,则其效果如同指定了值 noStitch 一样。
Example feTurbulence 展示了 feTurbulence 的各种参数设置的效果。
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"https://w3org.cn/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="450px" height="325px" viewBox="0 0 450 325"
xmlns="https://w3org.cn/2000/svg" version="1.1">
<title>Example feTurbulence - Examples of feTurbulence operations</title>
<desc>Six rectangular areas showing the effects of
various parameter settings for feTurbulence.</desc>
<g font-family="Verdana" text-anchor="middle" font-size="10" >
<defs>
<filter id="Turb1" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="2"/>
</filter>
<filter id="Turb2" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.1" numOctaves="2"/>
</filter>
<filter id="Turb3" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="8"/>
</filter>
<filter id="Turb4" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.1" numOctaves="4"/>
</filter>
<filter id="Turb5" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.4" numOctaves="4"/>
</filter>
<filter id="Turb6" filterUnits="objectBoundingBox"
x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.1" numOctaves="1"/>
</filter>
</defs>
<rect x="1" y="1" width="448" height="323"
fill="none" stroke="blue" stroke-width="1" />
<rect x="25" y="25" width="100" height="75" filter="url(#Turb1)" />
<text x="75" y="117">type=turbulence</text>
<text x="75" y="129">baseFrequency=0.05</text>
<text x="75" y="141">numOctaves=2</text>
<rect x="175" y="25" width="100" height="75" filter="url(#Turb2)" />
<text x="225" y="117">type=turbulence</text>
<text x="225" y="129">baseFrequency=0.1</text>
<text x="225" y="141">numOctaves=2</text>
<rect x="325" y="25" width="100" height="75" filter="url(#Turb3)" />
<text x="375" y="117">type=turbulence</text>
<text x="375" y="129">baseFrequency=0.05</text>
<text x="375" y="141">numOctaves=8</text>
<rect x="25" y="180" width="100" height="75" filter="url(#Turb4)" />
<text x="75" y="272">type=fractalNoise</text>
<text x="75" y="284">baseFrequency=0.1</text>
<text x="75" y="296">numOctaves=4</text>
<rect x="175" y="180" width="100" height="75" filter="url(#Turb5)" />
<text x="225" y="272">type=fractalNoise</text>
<text x="225" y="284">baseFrequency=0.4</text>
<text x="225" y="296">numOctaves=4</text>
<rect x="325" y="180" width="100" height="75" filter="url(#Turb6)" />
<text x="375" y="272">type=fractalNoise</text>
<text x="375" y="284">baseFrequency=0.1</text>
<text x="375" y="296">numOctaves=1</text>
</g>
</svg>![]() |
interface SVGFilterElement : SVGElement,
SVGURIReference,
SVGLangSpace,
SVGExternalResourcesRequired,
SVGStylable,
SVGUnitTypes {
readonly attribute SVGAnimatedEnumeration filterUnits;
readonly attribute SVGAnimatedEnumeration primitiveUnits;
readonly attribute SVGAnimatedLength x;
readonly attribute SVGAnimatedLength y;
readonly attribute SVGAnimatedLength width;
readonly attribute SVGAnimatedLength height;
readonly attribute SVGAnimatedInteger filterResX;
readonly attribute SVGAnimatedInteger filterResY;
void setFilterRes(in unsigned long filterResX, in unsigned long filterResY) raises(DOMException);
};interface SVGFilterPrimitiveStandardAttributes : SVGStylable {
readonly attribute SVGAnimatedLength x;
readonly attribute SVGAnimatedLength y;
readonly attribute SVGAnimatedLength width;
readonly attribute SVGAnimatedLength height;
readonly attribute SVGAnimatedString result;
};interface SVGFEBlendElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
// Blend Mode Types
const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0;
const unsigned short SVG_FEBLEND_MODE_NORMAL = 1;
const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2;
const unsigned short SVG_FEBLEND_MODE_SCREEN = 3;
const unsigned short SVG_FEBLEND_MODE_DARKEN = 4;
const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5;
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedString in2;
readonly attribute SVGAnimatedEnumeration mode;
};interface SVGFEColorMatrixElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
// Color Matrix Types
const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1;
const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2;
const unsigned short SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3;
const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4;
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedEnumeration type;
readonly attribute SVGAnimatedNumberList values;
};interface SVGFEComponentTransferElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
readonly attribute SVGAnimatedString in1;
};interface SVGComponentTransferFunctionElement : SVGElement {
// Component Transfer Types
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5;
readonly attribute SVGAnimatedEnumeration type;
readonly attribute SVGAnimatedNumberList tableValues;
readonly attribute SVGAnimatedNumber slope;
readonly attribute SVGAnimatedNumber intercept;
readonly attribute SVGAnimatedNumber amplitude;
readonly attribute SVGAnimatedNumber exponent;
readonly attribute SVGAnimatedNumber offset;
};interface SVGFEFuncRElement : SVGComponentTransferFunctionElement {
};
interface SVGFEFuncGElement : SVGComponentTransferFunctionElement {
};
interface SVGFEFuncBElement : SVGComponentTransferFunctionElement {
};
interface SVGFEFuncAElement : SVGComponentTransferFunctionElement {
};
interface SVGFECompositeElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
// Composite Operators
const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0;
const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1;
const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2;
const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3;
const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5;
const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedString in2;
readonly attribute SVGAnimatedEnumeration operator;
readonly attribute SVGAnimatedNumber k1;
readonly attribute SVGAnimatedNumber k2;
readonly attribute SVGAnimatedNumber k3;
readonly attribute SVGAnimatedNumber k4;
};interface SVGFEConvolveMatrixElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
// Edge Mode Values
const unsigned short SVG_EDGEMODE_UNKNOWN = 0;
const unsigned short SVG_EDGEMODE_DUPLICATE = 1;
const unsigned short SVG_EDGEMODE_WRAP = 2;
const unsigned short SVG_EDGEMODE_NONE = 3;
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedInteger orderX;
readonly attribute SVGAnimatedInteger orderY;
readonly attribute SVGAnimatedNumberList kernelMatrix;
readonly attribute SVGAnimatedNumber divisor;
readonly attribute SVGAnimatedNumber bias;
readonly attribute SVGAnimatedInteger targetX;
readonly attribute SVGAnimatedInteger targetY;
readonly attribute SVGAnimatedEnumeration edgeMode;
readonly attribute SVGAnimatedNumber kernelUnitLengthX;
readonly attribute SVGAnimatedNumber kernelUnitLengthY;
readonly attribute SVGAnimatedBoolean preserveAlpha;
};interface SVGFEDiffuseLightingElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedNumber surfaceScale;
readonly attribute SVGAnimatedNumber diffuseConstant;
readonly attribute SVGAnimatedNumber kernelUnitLengthX;
readonly attribute SVGAnimatedNumber kernelUnitLengthY;
};interface SVGFEDistantLightElement : SVGElement {
readonly attribute SVGAnimatedNumber azimuth;
readonly attribute SVGAnimatedNumber elevation;
};interface SVGFEPointLightElement : SVGElement {
readonly attribute SVGAnimatedNumber x;
readonly attribute SVGAnimatedNumber y;
readonly attribute SVGAnimatedNumber z;
};interface SVGFESpotLightElement : SVGElement {
readonly attribute SVGAnimatedNumber x;
readonly attribute SVGAnimatedNumber y;
readonly attribute SVGAnimatedNumber z;
readonly attribute SVGAnimatedNumber pointsAtX;
readonly attribute SVGAnimatedNumber pointsAtY;
readonly attribute SVGAnimatedNumber pointsAtZ;
readonly attribute SVGAnimatedNumber specularExponent;
readonly attribute SVGAnimatedNumber limitingConeAngle;
};interface SVGFEDisplacementMapElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
// Channel Selectors
const unsigned short SVG_CHANNEL_UNKNOWN = 0;
const unsigned short SVG_CHANNEL_R = 1;
const unsigned short SVG_CHANNEL_G = 2;
const unsigned short SVG_CHANNEL_B = 3;
const unsigned short SVG_CHANNEL_A = 4;
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedString in2;
readonly attribute SVGAnimatedNumber scale;
readonly attribute SVGAnimatedEnumeration xChannelSelector;
readonly attribute SVGAnimatedEnumeration yChannelSelector;
};interface SVGFEFloodElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
};
interface SVGFEGaussianBlurElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedNumber stdDeviationX;
readonly attribute SVGAnimatedNumber stdDeviationY;
void setStdDeviation(in float stdDeviationX, in float stdDeviationY) raises(DOMException);
};interface SVGFEImageElement : SVGElement,
SVGURIReference,
SVGLangSpace,
SVGExternalResourcesRequired,
SVGFilterPrimitiveStandardAttributes {
readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
};interface SVGFEMergeElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
};
interface SVGFEMergeNodeElement : SVGElement {
readonly attribute SVGAnimatedString in1;
};interface SVGFEMorphologyElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
// Morphology Operators
const unsigned short SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0;
const unsigned short SVG_MORPHOLOGY_OPERATOR_ERODE = 1;
const unsigned short SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedEnumeration operator;
readonly attribute SVGAnimatedNumber radiusX;
readonly attribute SVGAnimatedNumber radiusY;
};interface SVGFEOffsetElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedNumber dx;
readonly attribute SVGAnimatedNumber dy;
};interface SVGFESpecularLightingElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedNumber surfaceScale;
readonly attribute SVGAnimatedNumber specularConstant;
readonly attribute SVGAnimatedNumber specularExponent;
readonly attribute SVGAnimatedNumber kernelUnitLengthX;
readonly attribute SVGAnimatedNumber kernelUnitLengthY;
};interface SVGFETileElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
readonly attribute SVGAnimatedString in1;
};interface SVGFETurbulenceElement : SVGElement,
SVGFilterPrimitiveStandardAttributes {
// Turbulence Types
const unsigned short SVG_TURBULENCE_TYPE_UNKNOWN = 0;
const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2;
// Stitch Options
const unsigned short SVG_STITCHTYPE_UNKNOWN = 0;
const unsigned short SVG_STITCHTYPE_STITCH = 1;
const unsigned short SVG_STITCHTYPE_NOSTITCH = 2;
readonly attribute SVGAnimatedNumber baseFrequencyX;
readonly attribute SVGAnimatedNumber baseFrequencyY;
readonly attribute SVGAnimatedInteger numOctaves;
readonly attribute SVGAnimatedNumber seed;
readonly attribute SVGAnimatedEnumeration stitchTiles;
readonly attribute SVGAnimatedEnumeration type;
};