SVG: Getting an Anaglyph effect - svg

I'm trying to create a SVG filter that would create an Anaglyph effect.
What I've done so far is to duplicate some shapes to some red and blue shapes. Now, I would like to change the way (opacity...) those shapes overlap so I can get the anaglyph effect. How can I do this ? Do you know another SVG filter that would create this effect ? Thanks.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.48.1 r9760"
>
<defs>
<filter id="F1" filterUnits="userSpaceOnUse" x="0" y="0" width="100%" height="100%">
<feOffset in="SourceAlpha" dx="10" dy="0" result="L1"/>
<feOffset in="SourceAlpha" dx="-10" dy="0" result="R1"/>
<feComponentTransfer in="L1" result="L2">
<feFuncR type="table" tableValues="1 1 1 1"/>
<feFuncG type="table" tableValues="0 0 0 1"/>
<feFuncB type="table" tableValues="0 0 0 1"/>
</feComponentTransfer>
<feComponentTransfer in="R1" result="R2">
<feFuncR type="table" tableValues="0 0 0 1"/>
<feFuncG type="table" tableValues="0 0 0 1"/>
<feFuncB type="table" tableValues="1 1 1 1"/>
</feComponentTransfer>
<feMerge>
<feMergeNode in="L2"/>
<feMergeNode in="R2"/>
</feMerge>
</filter>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g filter="url(#F1)" style="stroke-opacity:0.5;">
<rect
style="opacity:1;fill:#5d7cd5;fill-opacity:1;stroke:#ca0000;stroke-width:10.80000019;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect2987"
width="234.28572"
height="168.57143"
x="120"
y="260.93362" />
<rect
style="opacity:1;fill:#008080;fill-opacity:1;stroke:#ca0000;stroke-width:10.80000019000000044;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect2989"
width="174.28572"
height="162.85715"
x="245.71428"
y="369.50504" />
<rect
style="opacity:1;fill:#aa4400;fill-opacity:1;stroke:#ca0000;stroke-width:10.80000019000000044;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect2991"
width="257.14285"
height="168.57143"
x="348.57144"
y="483.79074" />
<rect
style="opacity:1;fill:#6c5353;fill-opacity:1;stroke:#ca0000;stroke-width:10.80000019;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect2993"
width="422.85715"
height="225.71428"
x="285.71429"
y="226.6479" />
</g>
</g>
</svg>

OK, I think I found the answer. The additional filter was:
<feComposite operator="arithmetic"
in="L2"
in2="R2"
k1="0.5" k2="0.5" k3="0.5"
/>

Related

How to use feComponentTransfer inside a mask?

I am trying to use an SVG to mask an HTML element.
My SVG contains an feTurbulence filter that then uses feComponentTransfer to bring it down to hard black.
The SVG now looks like I want, but when I try to use it as a mask, it shows nothing.
If I remove the feFuncR feFuncG feFuncB I see the mask is working, it is just having unexpected results. How can I fix this so the mask is using the final output of the SVG?
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" viewBox="0 0 150 150">
<mask id="mask">
<filter id="filter" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.1" seed="5" />
<feComponentTransfer>
<feFuncA type="discrete" tableValues="0 0 0 1 1 1"/>
<feFuncR type="discrete" tableValues="0"/>
<feFuncG type="discrete" tableValues="0"/>
<feFuncB type="discrete" tableValues="0"/>
</feComponentTransfer>
</filter>
<rect x="0" y="0" width="100%" height="100%" filter="url(#filter)" fill="none" />
</mask>
</svg>
<div style="width:150px; height:150px; background:blue; mask:url(#mask);"></div>
Using a filter on mask contents doesn't seem to be supported. The good news is that filters can do masking (feComposite/in) - so just do it all in a filter.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" viewBox="0 0 150 150">
<filter id="mefilter" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.1" seed="5" />
<feComponentTransfer>
<feFuncA type="discrete" tableValues="0 0 0 1 1 1"/>
<feFuncR type="discrete" tableValues="0"/>
<feFuncG type="discrete" tableValues="0"/>
<feFuncB type="discrete" tableValues="0"/>
</feComponentTransfer>
<feComposite operator="in" in="SourceGraphic"/>
</filter>
</svg>
<div style="width:150px; height:150px; background:blue; filter: url(#mefilter);"></div>

Add concentric lines around a rect in svg

I try to create a rect with 3 borders around using filters.
The result should look like this:
but my result looks like this:
code:
<svg width=1000 height=1000 >
<rect width=300 height=50 rx=25 x=100 y=100 filter="url(#filter)" fill="white"></rect>
<filter id="filter">
<feFlood flood-color="RGBA(173, 15, 91, 1.00)" result="fill1"></feFlood>
<feMorphology in="SourceAlpha" operator="dilate" radius="8" result="radius1"></feMorphology>
<feComposite in="fill1" in2="radius1" operator="in" result="compose1"></feComposite>
<feFlood flood-color="RGBA(217, 145, 180, 1.00)" result="fill2"></feFlood>
<feMorphology in="SourceAlpha" operator="dilate" radius="16" result="radius2"></feMorphology>
<feComposite in="fill2" in2="radius2" operator="in" result="compose2"></feComposite>
<feFlood flood-color="RGBA(247, 231, 239, 1.00)" result="fill3"></feFlood>
<feMorphology in="SourceAlpha" operator="dilate" radius="24" result="radius3"></feMorphology>
<feComposite in="fill3" in2="radius3" operator="in" result="compose3"></feComposite>
<feMerge result="a452afbd-5e3f-4c25-abcf-3c77051dd340">
<feMergeNode in="compose3"></feMergeNode>
<feMergeNode in="compose2"></feMergeNode>
<feMergeNode in="compose1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</svg>
any idea how to get this right using filters.
If you want to retain the shape, you can't use feMorphology because it uses a square evenly weighted kernel. Instead you have to use a blur and an alpha boost (aka the gooey effect). (Also need to increase the filter region)
<svg width="1000px" height="1000px" >
<rect width=300 height=50 rx=25 x=100 y=100 filter="url(#filter)" fill="white"></rect>
<filter id="filter" x="-50%" y="-100%" height="400%" width="200%" color-interpolation-filters="sRGB">
<feFlood flood-color="RGBA(173, 15, 91, 1.00)" result="fill1"/>
<feGaussianBlur stdDeviation="8" in="SourceGraphic"/>
<feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -2" result="radius1"/>
<feComposite in="fill1" in2="radius1" operator="in" result="compose1"/>
<feFlood flood-color="RGBA(217, 145, 180, 1.00)" result="fill2"/>
<feGaussianBlur stdDeviation="8" in="compose1" />
<feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -2" result="radius2"/>
<feComposite in="fill2" in2="radius2" operator="in" result="compose2"/>
<feFlood flood-color="RGBA(247, 231, 239, 1.00)" result="fill3"/>
<feGaussianBlur stdDeviation="8" in="compose2"/>
<feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -2" result="radius3"/>
<feComposite in="fill3" in2="radius3" operator="in" result="compose3"/>
<feMerge result="a452afbd-5e3f-4c25-abcf-3c77051dd340">
<feMergeNode in="compose3"></feMergeNode>
<feMergeNode in="compose2"></feMergeNode>
<feMergeNode in="compose1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</svg>
You just neede to increase the filter bounds so they extend far enough outside the object being filtered.
The defaults are an additional 10% in all directions but that's not enough for your use case.
<svg width=1000 height=1000 >
<rect width=300 height=50 rx=25 x=100 y=100 filter="url(#filter)" fill="white"></rect>
<filter id="filter" y="-70%" height="240%">
<feFlood flood-color="RGBA(173, 15, 91, 1.00)" result="fill1"></feFlood>
<feMorphology in="SourceAlpha" operator="dilate" radius="8" result="radius1"></feMorphology>
<feComposite in="fill1" in2="radius1" operator="in" result="compose1"></feComposite>
<feFlood flood-color="RGBA(217, 145, 180, 1.00)" result="fill2"></feFlood>
<feMorphology in="SourceAlpha" operator="dilate" radius="16" result="radius2"></feMorphology>
<feComposite in="fill2" in2="radius2" operator="in" result="compose2"></feComposite>
<feFlood flood-color="RGBA(247, 231, 239, 1.00)" result="fill3"></feFlood>
<feMorphology in="SourceAlpha" operator="dilate" radius="24" result="radius3"></feMorphology>
<feComposite in="fill3" in2="radius3" operator="in" result="compose3"></feComposite>
<feMerge result="a452afbd-5e3f-4c25-abcf-3c77051dd340">
<feMergeNode in="compose3"></feMergeNode>
<feMergeNode in="compose2"></feMergeNode>
<feMergeNode in="compose1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</svg>
Couldn't you just draw this with separate paths instead?
<svg width="320" height="120" viewBox="0 0 320 120">
<rect x="10" y="10" width="300" height="100" rx="50" ry="50" fill="none" stroke="#fad" stroke-width="10"/>
<rect x="20" y="20" width="280" height="80" rx="40" ry="40" fill="none" stroke="#b58" stroke-width="10"/>
<rect x="30" y="30" width="260" height="60" rx="30" ry="30" fill="none" stroke="#603" stroke-width="10"/>
</svg>

Control the colour of multiple drop shadow filter in svg

I am trying to apply multiple dropshadow effects - each with a different colour using SVG, I can position the elements perfectly but I cannot figure out how to colour them independently. The following gets me 90% there but both shadows are the same colour:
<svg className={style.svg} viewBox={`0 0 150 150`}>
<defs>
<filter id="drop-shadow" x="-100%" y="-100%" width="300%" height="300%">
<feGaussianBlur in="SourceAlpha" stdDeviation="2" />
<feColorMatrix
in="offOut"
type="matrix"
values="0.2 0 0 0 0 0 0.2 0 0 1 0 0 0.2 0 0 0 0 0 1 0"
/>
<feOffset dx="-5" dy="5" result="offsetblur" />
<feOffset dx="10" dy="-10" result="offsetblur2" in="blur" />
<feComponentTransfer result="shadow1" in="offsetblur">
<feFuncA type="linear" slope="0.3" />
</feComponentTransfer>
<feComponentTransfer result="shadow2" in="offsetblur2">
<feFuncA type="linear" slope="0.3" />
</feComponentTransfer>
<feMerge>
<feMergeNode in="shadow1" />
<feMergeNode in="shadow2" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<circle
stroke="#ff00ff"
fill="#ff00ff"
cx=75
cy=75
r=55
strokeWidth=15
filter="url(#drop-shadow)"
/>
</svg>
CODEPEN
I copied this from one of the recommended answers here on stack overflow but I cant tailor it for my specific purposes. How do I colour each shadow independently?
Thanks in advance.
It's a bit more performant to use color matrix vs. component transfer if you can - browsers can do color matrix on the GPU. You can also get rid of a few steps and specify colors directly using the fifth column. SourceAlpha has color channels set to zero/black - so applying a multiplier them doesn't do anything.
<svg className={style.svg} viewBox={`0 0 150 150`}>
<defs>
<filter id="drop-shadow" x="-100%" y="-100%" width="300%" height="300%">
<feGaussianBlur in="SourceAlpha" stdDeviation="2" />
<feColorMatrix
type="matrix"
values="0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0.3 0"
/>
<feOffset dx="-5" dy="5" result="shadow1" />
<feOffset dx="10" dy="-10" result="offsetblur2" />
<feColorMatrix type="matrix" result="shadow2"
values="0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0"
/>
</feComponentTransfer>
<feMerge>
<feMergeNode in="shadow1" />
<feMergeNode in="shadow2" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<circle
stroke="#ff00ff"
fill="#ff00ff"
cx=75
cy=75
r=55
strokeWidth=15
filter="url(#drop-shadow)"
/>
</svg>
I used the feFuncR/G/B tag to change the filter colour like so:
<defs>
<filter id="drop-shadow" x="-100%" y="-100%" width="300%" height="300%">
<feGaussianBlur in="SourceAlpha" stdDeviation="5" />
<feOffset dx="-15" dy="15" result="offsetblur" />
<feOffset dx="25" dy="-25" result="offsetblur2" in="blur" />
<feComponentTransfer result="shadow1" in="offsetblur">
<feFuncA type="linear" slope="0.3" />
</feComponentTransfer>
<feComponentTransfer result="shadow2" in="offsetblur2">
<feFuncA type="linear" slope="0.2" />
<feFuncR type="linear" slope="2.0" intercept="1" />
<feFuncG type="linear" slope="2.0" intercept="1" />
<feFuncB type="linear" slope="2.0" intercept="1" />
</feComponentTransfer>
<feMerge>
<feMergeNode in="shadow1" />
<feMergeNode in="shadow2" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
Posting the answer so that it might help others in the same position.

discard all SourceGraphic colors/alpha and recolor?

I have a shape with a stroke. The fill is orange with 50% opacity (so alpha = .5 and rgb(255,112,0)) and the stroke is blue (no transparency).
Using filters, I've been trying to make a copy (similar to a drop shadow, but without the blur). I'd like the copy to be solid orange.
But I just can't seem to get this as feColorMatrix continues to use SourceGraphic values.
No idea why, but if my shape fill is no transparency, and I also use feComponentTransfer again, I can get the solid shape copy.
The shape on the right is the one I'd like to make solid orange (or any color and opacity I choose), regardless of shape/stroke fill/opacity.
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="960" height="540" class="slide" shape-rendering="geometricPrecision" fill-rule="evenodd">
<rect width="960" height="540" stroke="#385D8A" fill="white" stroke-width="3" class="testSlideBorder" />
<svg x="10" y="10" overflow="visible" stroke="#0000FF" stroke-miterlimit="8" stroke-width="4">
<defs>
<filter id="offsetColoredShape" height="500%" width="500%" x="-275%" y="-275%">
<feColorMatrix in="SourceAlpha" type="matrix" values="
0 0 0 0 1
0 0 0 0 0.439
0 0 0 0 0
0 0 0 1 0"
result="changeToOrangeFill"/>
<feComponentTransfer result="changedAgain">
<feFuncR type="linear" slope="1" />
<feFuncG type="linear" slope="0.439" />
<feFuncB type="linear" slope="0" />
<feFuncA type="linear" slope="1" />
</feComponentTransfer>
<feOffset dx="120"/>
</filter>
</defs>
<use xlink:href="#star" filter="url(#offsetColoredShape)" />
<path id="star" fill="rgb(255,112,0)" fill-opacity="0.5" d="M0,63.904L17.609,51.5L8.562,31.952L30.014,30.014L31.952,8.562L51.5,17.609L63.904,0L76.309,17.609L95.857,8.562L97.795,30.014L119.247,31.952L110.199,51.5L127.809,63.904L110.199,76.309L119.247,95.857L97.795,97.795L95.857,119.247L76.309,110.199L63.904,127.809L51.5,110.199L31.952,119.247L30.014,97.795L8.562,95.857L17.609,76.309Z" />
</svg>
</svg>
Notice in the <path/> that fill-opacity="0.5". If I change that to fill-opacity="1", it works as expected. Here's what that looks like:
<svg x="10" y="10" overflow="visible" fill="#4472C4" stroke="#0000FF" stroke-miterlimit="8" stroke-width="4">
<defs>
<filter id="offsetColoredShape" height="500%" width="500%" x="-275%" y="-275%">
<feColorMatrix in="SourceAlpha" type="matrix" values="
0 0 0 0 1
0 0 0 0 0.439
0 0 0 0 0
0 0 0 1 0"
result="changeToOrangeFill"/>
<feComponentTransfer result="changedAgain">
<feFuncR type="linear" slope="1" />
<feFuncG type="linear" slope="0.439" />
<feFuncB type="linear" slope="0" />
<feFuncA type="linear" slope="1" />
</feComponentTransfer>
<feOffset dx="120"/>
</filter>
</defs>
<use xlink:href="#star" filter="url(#offsetColoredShape)" />
<path id="star" fill="rgb(255,112,0)" fill-opacity="1" d="M0,63.904L17.609,51.5L8.562,31.952L30.014,30.014L31.952,8.562L51.5,17.609L63.904,0L76.309,17.609L95.857,8.562L97.795,30.014L119.247,31.952L110.199,51.5L127.809,63.904L110.199,76.309L119.247,95.857L97.795,97.795L95.857,119.247L76.309,110.199L63.904,127.809L51.5,110.199L31.952,119.247L30.014,97.795L8.562,95.857L17.609,76.309Z" />
</svg>
That's what I'm after no matter the shapes fill opacity.
Any thoughts as to how I can get a solid color (like black) and alpha = 100% of the SourceGraphic, and then be able to modify the color and it's opacity to any color/opacity I like?
You're not setting the alpha to 100% in your original feColorMatrix - you're multiplying the alpha by 1. If you want to set alpha to 100% - you should set the fifth column to 1 (not the fourth column).
Now the problem with that is that it sets all the background to 100% opacity as well so you get the rest of the graphic colored solid black.
But - we have a hack to get around this. Instead of using SourceAlpha - use SourceGraphic, and use the first three columns of the alpha row to boost the alpha of just the colored pixels to 100%. The result is a little crispy (because we nuke anti-aliasing) - but it does get you what you want and works for every color - including rgb(1,1,1).
If you know your colors are not going to be that close to black then, you can dial down those 255's to something more reasonable (like 5 or 10) & retain at least some of the anti-aliasing.
<svg x="10" y="10" overflow="visible" stroke="#0000FF" stroke-miterlimit="8" stroke-width="4" style="background:grey" color-interpolation-filters="sRGB">
<defs>
<filter id="offsetColoredShape" height="500%" width="500%" x="-275%" y="-275%">
<feColorMatrix in="SourceGraphic" type="matrix" values="
0 0 0 0 1
0 0 0 0 0.439
0 0 0 0 0
255 255 255 1 0"
result="changeToOrangeFill"/>
<feOffset dx="80"/>
</filter>
</defs>
<use xlink:href="#star" filter="url(#offsetColoredShape)" />
<path id="star" fill="rgb(255,112,0)" fill-opacity="0.5" d="M0,63.904L17.609,51.5L8.562,31.952L30.014,30.014L31.952,8.562L51.5,17.609L63.904,0L76.309,17.609L95.857,8.562L97.795,30.014L119.247,31.952L110.199,51.5L127.809,63.904L110.199,76.309L119.247,95.857L97.795,97.795L95.857,119.247L76.309,110.199L63.904,127.809L51.5,110.199L31.952,119.247L30.014,97.795L8.562,95.857L17.609,76.309Z" />
</svg>
You can put the #star path in the <defs> with no fill or stroke and you can use it the first time with the fill-opacity="0.5"and the blue stroke and the second time with the filter, if this is what you need.
svg{border:1px solid}
<svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-10 -10 360 150" class="slide" shape-rendering="geometricPrecision" fill-rule="evenodd">
<defs>
<path id="star" stroke-miterlimit="8" d="M0,63.904L17.609,51.5L8.562,31.952L30.014,30.014L31.952,8.562L51.5,17.609L63.904,0L76.309,17.609L95.857,8.562L97.795,30.014L119.247,31.952L110.199,51.5L127.809,63.904L110.199,76.309L119.247,95.857L97.795,97.795L95.857,119.247L76.309,110.199L63.904,127.809L51.5,110.199L31.952,119.247L30.014,97.795L8.562,95.857L17.609,76.309Z" />
<filter id="offsetColoredShape" height="500%" width="500%" x="-275%" y="-275%">
<feColorMatrix in="SourceAlpha" type="matrix" values="
0 0 0 0 1
0 0 0 0 0.439
0 0 0 0 0
0 0 0 1 0"
result="changeToOrangeFill"/>
<feComponentTransfer result="changedAgain">
<feFuncR type="linear" slope="1" />
<feFuncG type="linear" slope="0.439" />
<feFuncB type="linear" slope="0" />
<feFuncA type="linear" slope="1" />
</feComponentTransfer>
<feOffset dx="120"/>
</filter>
</defs>
<use xlink:href="#star" filter="url(#offsetColoredShape)" />
<use xlink:href="#star" fill="rgb(255,112,0)" fill-opacity="0.5" stroke="#0000FF" stroke-width="4" />
</svg>
UPDATE
The OP is commenting:
I'm wondering why, despite discarding all color values and setting alpha to 100% in feColorMatrix the alpha values are retained.
It's because the used element (i.e the #star) has fill-opacity="0.5". You need to use an element without the fill-opacity attribute.
In this simple example you can see that I can not modify the fill of the <use> since the used element has a fill. However I can add a stroke since the <use> element has no stroke:
<svg viewBox="0 0 100 50">
<circle id="c" fill="deepPink" stroke-width="5" cx="20" cy="25" r="10"></circle>
<use xlink:href="#c" x="50" fill="gold" stroke="skyBlue" />
</svg>
The OP is also commenting that the previous solution
doesn't work as the shapes are generated and the filters are simply inserted after the fact.
In the next demo I'm generating the #star. Next I'm generating the filtered <use> element and it works
const SVG_NS = 'http://www.w3.org/2000/svg';
const SVG_XLINK = "http://www.w3.org/1999/xlink";
const svg = document.querySelector("svg")
let d = "M0,63.904 L17.609,51.5L8.562,31.952L30.014,30.014L31.952,8.562L51.5,17.609L63.904,0L76.309,17.609L95.857,8.562L97.795,30.014L119.247,31.952L110.199,51.5L127.809,63.904L110.199,76.309L119.247,95.857L97.795,97.795L95.857,119.247L76.309,110.199L63.904,127.809L51.5,110.199L31.952,119.247L30.014,97.795L8.562,95.857L17.609,76.309Z"
let star = drawSVGelmt({d:d,id:"star"},"path", theDefs);
let use1 = document.createElementNS(SVG_NS, 'use');
use1.setAttributeNS(SVG_XLINK, 'xlink:href', '#star');
use1.setAttribute('class', 'filtered');
svg.appendChild(use1)
function drawSVGelmt(o,tag, parent) {
let elmt = document.createElementNS(SVG_NS, tag);
for (let name in o) {
if (o.hasOwnProperty(name)) {
elmt.setAttributeNS(null, name, o[name]);
}
}
parent.appendChild(elmt);
return elmt;
}
.filtered{filter:url(#offsetColoredShape)}
<svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-10 -10 360 150" class="slide" shape-rendering="geometricPrecision" fill-rule="evenodd">
<defs id="theDefs">
<filter id="offsetColoredShape" height="500%" width="500%" x="-275%" y="-275%">
<feColorMatrix in="SourceAlpha" type="matrix" values="
0 0 0 0 1
0 0 0 0 0.439
0 0 0 0 0
0 0 0 1 0"
result="changeToOrangeFill"/>
<feComponentTransfer result="changedAgain">
<feFuncR type="linear" slope="1" />
<feFuncG type="linear" slope="0.439" />
<feFuncB type="linear" slope="0" />
<feFuncA type="linear" slope="1" />
</feComponentTransfer>
<feOffset dx="120"/>
</filter>
</defs>
<use xlink:href="#star" fill="rgb(255,112,0)" fill-opacity="0.5" stroke="#0000FF" stroke-width="4" />
</svg>

SVG filter to map alpha values to RGB values in a table?

I see how to use feComponentTransfer to adjust RGBA values using a table and tableValues.
But is there a way to adjust the R, G, or B values using alpha values as input (for example)?
Why? Say I composite many translucent shapes, resulting in different opacities where these shapes overlap. I would like to use these opacity values to adjust the RGB using a lookup table based on the opacity of each pixel.
For example, in this image the ellipse, squares, and text are drawn with alpha 0.1. Overlapping regions have higher alpha values.
How would I map every pixel in this image with alpha 0.1 to rgba(255,0,0,1) and everywhere with alpha 0.2 to rgba(0,255,0,1) (and interpolate the replacement colors between those two alpha values on the anti-aliased edges)? More colors would be assigned to all other alpha values up to 1.
Easy to make such a lookup table.
But how to apply to image with a svg filter?
You can achieve it, but it is a multistep process, and you'll have to see about performance and maintainability yourself.
My example code divides the opacity values into four equally-spaced ranges: 0.2...0.4...0.6...0.8...1. The range 0...0.2 is mapped to transparency.
For each of the four colored ranges you need to combine three filter primitives:
pick up SourceAlpha as input, and apply <feComponentTransfer> to the alpha channel with type discrete such that only one range is mapped to opacity="1"
fill the filter area with <feFlood> in the assigned color
combine the first and second result with <feComposite> and operator="in", so that only the mapped values are colored
Then, merge all the different monochromatic parts together with <feMerge>.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="200">
<linearGradient id="sourceGradient" x1="0" x2="1" y1="0" y2="0">
<stop style="stop-color:#000000;stop-opacity:0" offset="0" />
<stop style="stop-color:#000000;stop-opacity:1" offset="1" />
</linearGradient>
<filter id="filter">
<feComponentTransfer in="SourceAlpha" result="step1">
<feFuncA type="discrete" tableValues="0 1 0 0 0"/>
</feComponentTransfer>
<feFlood flood-color="rgb(255,0,0)" />
<feComposite operator="in" in2="step1" result="color1" />
<feComponentTransfer in="SourceAlpha" result="step2">
<feFuncA type="discrete" tableValues="0 0 1 0 0"/>
</feComponentTransfer>
<feFlood flood-color="rgb(255,255,0)" />
<feComposite operator="in" in2="step2" result="color2" />
<feComponentTransfer in="SourceAlpha" result="step3">
<feFuncA type="discrete" tableValues="0 0 0 1 0"/>
</feComponentTransfer>
<feFlood flood-color="rgb(0,255,0)" />
<feComposite operator="in" in2="step3" result="color3" />
<feComponentTransfer in="SourceAlpha" result="step4">
<feFuncA type="discrete" tableValues="0 0 0 0 1"/>
</feComponentTransfer>
<feFlood flood-color="rgb(0,0,255)" />
<feComposite operator="in" in2="step4" result="color4" />
<feMerge>
<feMergeNode in="color1" />
<feMergeNode in="color2" />
<feMergeNode in="color3" />
<feMergeNode in="color4" />
</feMerge>
</filter>
<rect fill="url(#sourceGradient)" x="50" y="25" width="300" height="50" id="rect" />
<use xlink:href="#rect" y="100" filter="url(#filter)" />
</svg>
interpolate the replacement colors between those two alpha values on the anti-aliased edges
I am not sure I understand that, but type="table" for component transfer results in a continuous scale. The result after merge has opacities below 1 in most places, so you would need some final steps to ramp that up again.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="200">
<linearGradient id="sourceGradient" x1="0" x2="1" y1="0" y2="0">
<stop style="stop-color:#000000;stop-opacity:0" offset="0" />
<stop style="stop-color:#000000;stop-opacity:1" offset="1" />
</linearGradient>
<filter id="filter" x="0" y="0" width="1" height="1">
<feComponentTransfer in="SourceAlpha" result="step1">
<feFuncA type="table" tableValues="0 1 0 0 0"/>
</feComponentTransfer>
<feFlood flood-color="rgb(255,0,0)" />
<feComposite operator="in" in2="step1" result="color1" />
<feComponentTransfer in="SourceAlpha" result="step2">
<feFuncA type="table" tableValues="0 0 1 0 0"/>
</feComponentTransfer>
<feFlood flood-color="rgb(255,255,0)" />
<feComposite operator="in" in2="step2" result="color2" />
<feComponentTransfer in="SourceAlpha" result="step3">
<feFuncA type="table" tableValues="0 0 0 1 0"/>
</feComponentTransfer>
<feFlood flood-color="rgb(0,255,0)" />
<feComposite operator="in" in2="step3" result="color3" />
<feComponentTransfer in="SourceAlpha" result="step4">
<feFuncA type="table" tableValues="0 0 0 0 1"/>
</feComponentTransfer>
<feFlood flood-color="rgb(0,0,255)" />
<feComposite operator="in" in2="step4" result="color4" />
<feMerge result="merged">
<feMergeNode in="color1" />
<feMergeNode in="color2" />
<feMergeNode in="color3" />
<feMergeNode in="color4" />
</feMerge>
<feComponentTransfer in="SourceAlpha" result="capped">
<feFuncA type="discrete" tableValues="0 1 1 1 1"/>
</feComponentTransfer>
<feComposite operator="atop" in="merged" in2="capped" />
</filter>
<rect fill="url(#sourceGradient)" x="50" y="25" width="300" height="50" id="rect" />
<use xlink:href="#rect" y="100" filter="url(#filter)" />
</svg>

Resources