我需要一种方法来为基于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文档中的呈现方式:
这是原始的PNG图形(odd_shape.png):
问题1 :如何重复使用前2个过滤器(drop-shadow
和outer-stroke
),这样我就可以在组合过滤器中应用它们outer-stroke-drop-shadow
而不是必须复制和粘贴它们。
问题2:是否可以参数化自定义过滤器,以便指定笔触颜色或投影的透明度等内容?这将使它们更加可重复使用。
感谢。
答案 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>
结果:
答案 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)。