参数化和重用HTML5中定义的自定义SVG过滤器?

时间:2014-02-13 19:40:16

标签: html css html5 svg svg-filters

我需要一种方法来为基于alpha蒙版的透明PNG图像添加“笔画”(轮廓)和阴影效果,我唯一能找到的解决方案是使用自定义SVG滤镜。 (注意:我需要这些效果的网络应用程序仅供我自己使用,因此可以解决此解决方案与旧版浏览器不兼容的问题。继续......)

之前我从未使用过SVG,但单独创建笔画和阴影滤镜非常简单。遗憾的是,我找不到创建组合效果的方法,而无需将过滤器实际复制并粘贴到新的过滤器中,如下面的代码所示:

<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg">

    <!-- drop shadow -->
    <filter id="drop-shadow">
        <feGaussianBlur in="SourceAlpha" stdDeviation="4" />
        <feOffset result="m_offsetBlurred" dx="12" dy="12" />
        <feFlood result="m_floodTrans50" flood-color="rgba(0,0,0,0.5)" />
        <feComposite result="m_offsetBlurredTrans50" in="m_floodTrans50" in2="m_offsetBlurred" operator="in" />
        <feMerge>
            <feMergeNode in="m_offsetBlurredTrans50" />
            <feMergeNode in="SourceGraphic" />
        </feMerge>
    </filter>


    <!-- outer stroke -->
    <filter id="outer-stroke">
        <!-- create rectangle of the desired color -->
        <feFlood result="m_floodRect" flood-color="black" />

        <!-- create copy of png's alpha mask and expand -->
        <feMorphology result="m_expandedMask" in="SourceAlpha" operator="dilate" radius="1" />

        <!-- "cut out" a section of the flood fill matching the expanded copy -->
        <feComposite result="m_expandedColored" in="m_floodRect" in2="m_expandedMask" operator="in" />

        <!-- blend it behind the original shape to create the outline effect -->
        <feBlend in="SourceGraphic" in2="m_expandedColored" mode="normal" />
    </filter>


    <!-- drop shadow & outer stroke (must copy & paste the 2 filters above, which violates the DRY principle) -->
    <filter id="outer-stroke-drop-shadow">
        <!-- create rectangle of the desired color -->
        <feFlood result="m_floodRect" flood-color="black" />

        <!-- create copy of png's alpha mask and expand -->
        <feMorphology result="m_expandedMask" in="SourceAlpha" operator="dilate" radius="1" />

        <!-- "cut out" a section of the flood fill matching the expanded copy -->
        <feComposite result="m_expandedColored" in="m_floodRect" in2="m_expandedMask" operator="in" />

        <!-- blend it behind the original shape to create the outline effect -->
        <feBlend result="m_stroked" in="SourceGraphic" in2="m_expandedColored" mode="normal" />

        <!-- add drop shadow -->
        <feGaussianBlur result="m_blurred" in="SourceAlpha" stdDeviation="4" />
        <feOffset result="m_offsetBlurred" in="m_blurred" dx="12" dy="12" />
        <feFlood result="m_floodTrans50" flood-color="rgba(0,0,0,0.5)" />
        <feComposite result="m_offsetBlurredTrans50" in="m_floodTrans50" in2="m_offsetBlurred" operator="in" />
        <feMerge>
            <feMergeNode in="m_offsetBlurredTrans50" />
            <feMergeNode in="m_stroked" />
        </feMerge>
    </filter>
</svg>


<style>
    .fx_drop_shadow              { filter: url('#drop-shadow'); }
    .fx_outer_stroke             { filter: url('#outer-stroke'); }
    .fx_outer_stroke_drop_shadow { filter: url('#outer-stroke-drop-shadow'); }
</style>


<div>
    <img src="gfx/odd_shape.png" />
    <img src="gfx/odd_shape.png" class="fx_drop_shadow" />
    <img src="gfx/odd_shape.png" class="fx_outer_stroke" />
    <img src="gfx/odd_shape.png" class="fx_outer_stroke_drop_shadow" />
</div>

以下是上述代码在HTML5文档中的呈现方式:

SVG filters applied to a PNG image

这是原始的PNG图形(odd_shape.png):

enter image description here

问题1 :如何重复使用前2个过滤器(drop-shadowouter-stroke),这样我就可以在组合过滤器中应用它们outer-stroke-drop-shadow而不是必须复制和粘贴它们。

问题2:是否可以参数化自定义过滤器,以便指定笔触颜色或投影的透明度等内容?这将使它们更加可重复使用。


感谢。

3 个答案:

答案 0 :(得分:4)

这是一个完整的解决方案,适用于我测试的两个浏览器(Firefox和Chrome)......

问题1的解决方案:我测试的所有浏览器都不支持在filter property中指定多个过滤器,因此最好(也许是唯一)组合用户定义过滤器的方法正在使用Michael Mullany建议的技术:在嵌套的<g>元素中按顺序应用它们,根据需要创建过滤器图形。

问题2的解决方案:W3C有SVG Parameters的工作草案,草稿包含polyfill script,用于使用和测试建议的功能。参数通过param()功能属性值(例如param(shadowColor) black)声明,并通过类似查询字符串的接口(例如foo.svg?shadowColor=red)或{{1}的子元素定义容器(例如,<object>)。

下面提供了两种解决方案的演示代码,以及Firefox的截图。

<小时/> mypage.html中的

<param name="shadowColor" value="red"/>

<小时/> 在filters.svg中

<object type="image/svg+xml" data="filters.svg?osColor=lime&dsAlpha=0.4"></object>
<object type="image/svg+xml" data="filters.svg?osColor=white&osWidth=4&dsAlpha=0.8&dsBlurSigma=8&dsOffsetX=32"></object>

结果:

enter image description here

答案 1 :(得分:2)

回答问题1:

Filter Effects spec允许您在线性列表中有多个效果,例如:

filter: url(#outer-stroke) drop-shadow(5px 5px 10px black);

甚至:

filter: url(#outer-stroke) url(#drop-shadow);

是否实施这是另一个问题。在Chrome中,您目前只能以这种方式合并shorthand syntax。效果将按照您指定的顺序应用。

回答问题2:

如果你使用drop-shadow shorthand,你可以将阴影颜色指定为rgba,这会给你不透明度。

答案 2 :(得分:1)

SVG 1.1过滤规范包含include another filter by reference的功能,但只有IE10 +(和Firefox - 感谢Robert!)支持此功能。您可以通过在不同级别的元素嵌套中应用它们来组合过滤器,也就是使用包装器组元素。虽然它不是特别优雅。

无法自行参数化SVG过滤器(当然,您可以通过JavaScript执行任何操作)。该规范包括使用笔触和填充对象作为过滤器输入的功能,但这些只在今天的Firefox和IE10 +中支持(没有Chrome,没有Safari)。