Parameterizing and reusing custom SVG filters defined in HTML5?

I needed a way to add a “stroke” (outline) and a drop effect to a transparent PNG image based on its alpha mask, and the only solution I could find was to use custom SVG filters. (Note: The web application for which I need these effects is for my personal use, so it’s normal that this solution is not compatible with older browsers. Moving ...)

I had never used SVG before, but it was pretty simple to create custom hatch and drop filters. Unfortunately, I could not find a way to create a combined effect without actually copying and pasting the filters into a new one, as shown in the code below:

<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 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 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>

Here's how the code above will display in an HTML5 document:

SVG filters applied to a PNG image

And here is the original PNG graphics (odd_shape.png):

enter image description here

Question 1: . How can I reuse the first 2 filters ( drop-shadowand outer-stroke), so I can just apply them in the combined filter ( outer-stroke-drop-shadow) instead of copying and pasting them.

Question 2: Is it possible to parameterize custom filters so that I can specify parameters such as stroke color or shadow transparency? This would make them even more reusable.


.

+3
3

, , (Firefox Chrome)...

1: , , (, , ) - , : <g>, .

2: W3C SVG, polyfill script . param() (, param(shadowColor) black) (, foo.svg?shadowColor=red) <object> (, <param name="shadowColor" value="red"/>).

- , Firefox.


mypage.html:
<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>


filters.svg:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300px" height="320px" viewBox="0 0 300 320">
    <defs>
        <filter id="dropShadow" width="150%">
            <feGaussianBlur in="SourceAlpha" stdDeviation="param(dsBlurSigma) 4" />
            <feOffset result="m_offsetBlurred" dx="param(dsOffsetX) 12" dy="param(dsOffsetY) 12" />
            <feComponentTransfer result="m_offsetBlurredTranslucent" in="m_offsetBlurred">
                <feFuncA type="linear" slope="param(dsAlpha) 0.5" />
            </feComponentTransfer>
            <feMerge>
                <feMergeNode in="m_offsetBlurredTranslucent" />
                <feMergeNode in="SourceGraphic" />
            </feMerge>
        </filter>
        <filter id="outerStroke" width="150%">
            <feFlood result="m_floodRect" flood-color="param(osColor) black" />
            <feMorphology result="m_expandedMask" in="SourceAlpha" operator="dilate" radius="param(osWidth) 1" />
            <feComposite result="m_expandedColored" in="m_floodRect" in2="m_expandedMask" operator="in" />
            <feBlend in="SourceGraphic" in2="m_expandedColored" mode="normal" />
        </filter>
    </defs>

    <!-- combine stroke & drop shadow -->
    <g style='filter:url(#dropShadow);' width='300' height='320'>
        <g style='filter:url(#outerStroke);'>
            <image width='240' height='280' xlink:href="gfx/odd_shape.png"></image>
        </g>
    </g>

    <!-- use polyfill from http://dev.w3.org/SVG/modules/param/master/SVGParamPrimer.html -->
    <script type="text/ecmascript" xlink:href="http://dev.w3.org/SVG/modules/param/master/param.js" />
</svg>

:

enter image description here

+3

1:

, :

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

:

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

2:

, rgba, .

+2

SVG 1.1 , IE10 + ( Firefox - Robert!) . , aka . .

SVG (, , , , JavaScript). , Firefox IE10 + ( Chrome, Safari).

+1
source

All Articles