Multiple Filters for Single Object in SVG
Asked Answered
W

4

21

I want to put two filters on my circle. (Maybe more)

I've tried doing:

filter="url(#f1);url(#f2)"

And:

filter="url(#f1,#f2)"

And:

filter="url(#f1 #f2)"

But none of them work. How can I approach this problem?

Wasson answered 15/1, 2013 at 13:3 Comment(0)
M
22

You could add multiple effects in one filter, however if you want to stack the filters up, first group the object and then apply the other filter to your object.

<g filter="url(#f2)">
<rect width="90" height="90" stroke="green" stroke-width="3" fill="yellow" filter="url(#f1)"/>
</g>
Montagnard answered 15/1, 2013 at 14:35 Comment(6)
Nope. That's even worse than before. That just gets rid of all my filters inside the group.Wasson
@BadgerGirl: Interestingly, the example doesn't work in Opera. My intuition would have said the total opposite (like "if it works anywhere, then in Opera").Idolize
That's weird, maybe somebody else can come up with a better solution.Montagnard
Oh really? This is strange because this example works for me in Opera.Wasson
@BadgerGirl: Ok, thanks for the "fiddle" :) Yes, you're right, it does work, but only one way round. You see I want the "f1" to be the one in the group, and "f2" to be in <rect>, but it doesn't work that way round :/Wasson
Okay, you answered my question. Thanks for your help :) However, it would help me if you were able to tell me why it only works a certain way round. Thanks again :)Wasson
A
20

I know this is a very old question, but for people referencing this, you can also just separate your filter functions with spaces - filter="url(#f1) url(#f2)" should work

See: https://css-tricks.com/almanac/properties/f/filter/

Appurtenant answered 18/9, 2020 at 15:55 Comment(4)
I don't know why this was downvoted, it's currently a viable solution (tested in Firefox and Chrome), provided that f2's input is SourceGraphicPing
This method made my SVG darker somehow. But if I combine the filters using <g> like Badger Cat suggests, this is not a problemBrigitte
@HolgerL Yes, when I try this method, I run into the strange darking problem too. I posted a question about it: #73067646Wagtail
This does work in the browser, but not in Inkscape (v1.2.1). As alternative, create a dedicated group for each filter (bad for the SVG hierarchy but works).Duchess
V
7

Start with an identity feColorMatrix and name the result currentGraphic for example. Use that as 'in' for each filter element bundle/transaction start and as 'result' for the final operation of the bundle. The next element bundle picks it up at 'in'='currentGraphic', etc.

Vinny answered 29/4, 2013 at 14:56 Comment(1)
Can you make an example?Angus
S
0

Here's a below example I've been working on for a project, where I blend together 5 different layers in a single SVG. The code is slightly more tedious but it's reliable.

It's grouped into 2 darker layers, blended with a multiply mode, then 2 lighter layers blended with a screen mode.

The last filter then blends together these 2 filters using a soft-light mode, and then renders over the top of a grey base layer - useful for filling any blanks caused by opacity stops.

I have found this link very useful for determining the correct blend modes: https://oreillymedia.github.io/Using_SVG/guide/blend-modes.html or github link to the same resource is: https://github.com/oreillymedia/Using_SVG/blob/master/guide/blend-modes.html

<?xml version="1.0" standalone="yes" ?>
<!-- note: xmlns link is required to use namespaces later -->
<svg width="100px" height="100px" viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <!-- define 4 different radial filters -->
        <radialGradient
            id="grad1"
            cx="0.25"
            cy="0.25"
            r="0.5"
            fx="0.25"
            fy="0.25"
            spreadMethod="pad">
            <stop offset="0%" stop-color="#900000" />
            <stop offset="100%" stop-opacity="0.0" stop-color="#900000" />
        </radialGradient>
        <radialGradient
            id="grad2"
            cx="0.75"
            cy="0.25"
            r="0.5"
            fx="0.75"
            fy="0.25"
            spreadMethod="pad">
            <stop offset="0%" stop-color="#ffffff" />
            <stop offset="100%" stop-opacity="0.0" stop-color="#ffffff" />
        </radialGradient>
        <radialGradient
            id="grad3"
            cx="0.25"
            cy="0.75"
            r="0.5"
            fx="0.25"
            fy="0.75"
            spreadMethod="pad">
            <stop offset="0%" stop-color="#bfbfff" />
            <stop offset="100%" stop-opacity="0.0" stop-color="#bfbfff" />
        </radialGradient>
        <radialGradient
            id="grad4"
            cx="0.75"
            cy="0.75"
            r="0.5"
            fx="0.75"
            fy="0.75"
            spreadMethod="pad">
            <stop offset="0%" stop-color="#009000" />
            <stop offset="100%" stop-opacity="0.0" stop-color="#009000" />
        </radialGradient>
        
        <!-- define a base rectangle at 50% grey -->
        <rect id="rect-base" x="0" y="0" width="100" height="100" fill="#ff0000" />
        
        <!-- define 4 rectangles and apply above filters to each one -->
        <rect id="grad1-rect" x="0" y="0" width="100" height="100" fill="url(#grad1)"/>
        <rect id="grad2-rect" x="0" y="0" width="100" height="100" fill="url(#grad2)"/>
        <rect id="grad3-rect" x="0" y="0" width="100" height="100" fill="url(#grad3)"/>
        <rect id="grad4-rect" x="0" y="0" width="100" height="100" fill="url(#grad4)"/>

        <!-- define a filter which combines the two darker gradient filled rectangles -->
        <filter id="fil-dark" x="0%" y="0%" height="100%" width="100%">
            <feImage xlink:href="#grad1-rect" result="fil-1A" x="0" y="0" />
            <feImage xlink:href="#grad4-rect" result="fil-1B" x="0" y="0" />
            <feBlend in="fil-1A" in2="fil-1B" mode="multiply" result="blendedGrad1"/>
            <feComposite in="blendedGrad1" in2="SourceGraphic" operator="in"/>
        </filter>
        
        <!-- define a filter which combines the two lighter gradient filled rectangles -->
        <filter id="fil-light" x="0%" y="0%" height="100%" width="100%">
            <feImage xlink:href="#grad2-rect" result="fil-2A" x="0" y="0" />
            <feImage xlink:href="#grad3-rect" result="fil-2B" x="0" y="0" />
            <feBlend in="fil-2A" in2="fil-2B" mode="screen" result="blendedGrad2"/>
            <feComposite in="blendedGrad2" in2="SourceGraphic" operator="in"/>
        </filter>
        
        <!-- define 2 rectangles that are filled with the light and dark filter results -->
        <rect id="filter1-rect" filter="url(#fil-dark)" x="0" y="0" width="100" height="100"/>
        <rect id="filter2-rect" filter="url(#fil-light)" x="0" y="0" width="100" height="100"/>
        
        <!-- define a final filter which combines the two rectangles which each contain the result of another filter -->
        <filter id="fil-blend" x="0%" y="0%" height="100%" width="100%">
            <feImage xlink:href="#filter1-rect" result="fil-3A" x="0" y="0" />
            <feImage xlink:href="#filter2-rect" result="fil-3B" x="0" y="0" />
            <feBlend in="fil-3A" in2="fil-3B" mode="soft-light" result="blendedGrad3"/>
            <feComposite in="blendedGrad3" in2="SourceGraphic" operator="in"/>
        </filter>
        
    </defs>
    
    <!-- create a base layer rectangle filled with 50% grey -->
    <rect x="0" y="0" width="100" height="100" fill="#7f7f7f"/>
    <!-- add a second rectangle on top filled with the final filter result -->
    <rect filter="url(#fil-blend)" x="0" y="0" width="100" height="100"/>
</svg>

Took me a bit of working out so hopefully it might be useful to someone else.

Sturm answered 30/5 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.