SVG stroke as glued lines - svg

Is there a way to define stroke of a single polygon so that it would look like multiple glued polygons? See this image:

No, not currently. (In the future, Vector Effects may let you do this.)
For the moment, you would need to have two polygons drawn with different stroke colours and thicknesses, and then use a clipping path to make sure that it looks like the thicker stroke does not also paint on the inside of the shape. For example:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="100" height="100">
<defs>
<polygon id="p" points="20,10 10,60 30,50 50,30"/>
<clipPath id="c">
<!-- a 100x100 square with the polygon cut out of it -->
<path d="M0,0 100,0 100,100 0,100 z M20,10 10,60 30,50 50,30 z"/>
</clipPath>
</defs>
<rect width="100" height="100"/>
<g clip-path="url(#c)" fill="none">
<use xlink:href="#p" stroke="yellow" stroke-width="8"/>
<use xlink:href="#p" stroke="blue" stroke-width="4"/>
</g>
</svg>

As with the last answer, you need 2 paths. However I would use 2 donut holes where the hole has nearly the diameter of the whole ring.The thing to note is that the outside of the inner ring forms the inside of the outer ring. Obviously stroke-width is zero.

You can emulate this with a morphology filter.
<svg width="2000px" height="2000px" viewBox="0 0 4000 4000">
<defs>
<filter id="dual-line" primitiveUnits="userSpaceOnUse">
<feColorMatrix result="just-stroke" type="matrix" values="0 0 0 0 0
0 1 0 0 0
0 0 1 0 0
-1 0 0 1 0"/>
<feColorMatrix in="SourceGraphic" result="just-fill" type="matrix"
values="0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0"/>
<feMorphology in="just-stroke" operator="dilate" radius="5"/>
<feGaussianBlur stdDeviation="6"/>
<feComponentTransfer result="pre-outer">
<feFuncA type="table" tableValues="0 0 .75 1">
</feComponentTransfer>
<feColorMatrix result="blackstroke" in="just-stroke" type="matrix" values=" 0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0"/>
<feComposite operator="over" in2="pre-outer" in="blackstroke"/>
<feComposite operator="in" in2="just-fill"/>
</filter>
</defs>
<g filter="url(#dual-line)">
<path d="M100 800 C 400 100, 650 100, 950 800 S 1500 1500, 100 800" stroke-width="5" stroke="green" fill="red"/>
</g>
</svg>

Related

Svg filter get outline of two blurred Objects

I have Two squares.
The end goal is to get the rounded outline of two merged svg objects. So, to achieve this, I first blurred them, with
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
Then, I multiplied the opacity by 30 and subtracted 255*-9, increasing the contrast and merging the two shapes
<feColorMatrix
in="blur"
type="matrix"
values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 30 -9"
result="goo"
/>
But the result I want is not this. I want to get the outline of this shape. Is there a way to do this?
If you want just the outline, add a feMorphology/dilate and a composite/out to your filter.
(If you want the original squares subtracted from the goo, then omit the feMorphology and change "goo" to SourceGraphic in the feComposite/out.)
<svg width="800px" height="600px" viewBox=" 0 0 400 400">
<defs>
<filter id="outline" x="-50%" y="-50%" height="200%" width="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
<feColorMatrix type="matrix"
values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 30 -9" result="goo"/>
<feMorphology operator="dilate" radius="1"/>
<feComposite operator="out" in2="goo"/>
/>
</filter>
</defs>
<g filter="url(#outline)">
<rect fill="red" x="10" y="30" width="100" height="100"/>
<rect fill="red" x="120" y="30" width="100" height="100"/>
</g>
</svg>

How do get stdDeviation in SVG to be responsive?

I use the following SVG filter to round the corners of my clip-path path:
<svg style="visibility: hidden;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="round">
<feGaussianBlur in="SourceGraphic" stdDeviation="15" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9" result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
</defs>
</svg>
The result:
The problem, here is the same result on much higher resolution:
How do I make the stdDeviation="15" part of the code responsive, so that the edges will be rounded by the same amount, indifferent of the resolution?
My site / divs dimensions are set in vw units, if that matters.
Thanks in advance!
Set the value of the blur using objectBoundingBox units. Like so:
<svg style="visibility: hidden;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="round" primitiveUnits="objectBoundingBox">
<feGaussianBlur in="SourceGraphic" stdDeviation=".02" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9" result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
</defs>
</svg>

Antialias SVG text before filter is applied?

SVG filters rasterize their source image, which means filtered text won't be anti-aliased, resulting in jagged edges.
Is there a workaround for this? Perhaps another filter can be used to emulate anti-aliasing, or maybe I can somehow anti-alias the text before the filter is applied?
Relevant Filter:
<filter id="f">
<feGaussianBlur in="SourceGraphic" stdDeviation="0" result="blur" />
<feColorMatrix
in="blur"
mode="matrix"
values="1 0 0 0 0
0 1 0 0 0
1 0 1 0 0
0 0 0 15 -8"
result="goo"
/>
<feComposite in="SourceGraphic" in2="goo" operator="atop" />
</filter>
Is there a workaround for this? Perhaps another filter can be used to
emulate anti-aliasing, or maybe I can somehow anti-alias the text
before the filter is applied?
This answer went into detail on the issue.
As a compromise solution, you can try:
Choose less contrasting colors for the color of letters and background
Apply the attribute shape-rendering =" crispEdges" to the font
Choose a font that renders sharper edges
For example, your chosen font font-family =" cursive " looks like this:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="400" height="600" viewBox="0 0 400 400" >
<text x="35" y="150" font-size="100px" fill="black" font-family="cursive"> HELLO </text>
</svg>
font-family = "Monotype Corsiva" looks better
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="400" height="200" viewBox="0 0 400 200" >
<rect width="100%" height="100%" fill="silver" />
<text x="35" y="120" font-size="100px" fill="#444444" shape-rendering="crispEdges" font-family="Monotype Corsiva" > HELLO </text>
</svg>
Applying an SVG filter to smooth jagged edges
For the filter feGaussianBlur the parameters are selected (the last
row of the matrix) 0 0 0 29 -1
For the filter feComposite operator="atop"
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="400" height="200" viewBox="0 0 400 200" >
<defs>
<filter id="f">
<feGaussianBlur in="SourceGraphic" stdDeviation="1" result="blur" >
</feGaussianBlur>
<feColorMatrix in="blur" type="matrix"
values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 29 -1"
result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
</defs>
<rect width="100%" height="100%" fill="silver" />
<text filter="url(#f)" x="35" y="120" font-size="100px" fill="#444444" shape-rendering="crispEdges" font-family="Monotype Corsiva" > HELLO </text>
</svg>
Filter animation
I'm animating the stdDeviation of the feGaussianBlur
As I understood from #aleclarson's comment you want to animate the filter attribute
<animate attributeName="stdDeviation" begin="0s" dur="8s"
repeatCount="indefinite" values="1;6;12;12;6;1;1" />
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="400" height="200" viewBox="0 0 400 200" >
<defs>
<filter id="f">
<feGaussianBlur in="SourceGraphic" stdDeviation="1" result="blur" >
<animate attributeName="stdDeviation" begin="0s" dur="8s" repeatCount="indefinite" values="1;6;12;12;6;1;1" />
</feGaussianBlur>
<feColorMatrix in="blur" type="matrix"
values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 29 -1"
result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
</defs>
<text filter="url(#f)" x="35" y="120" font-size="100px" fill="#111111" shape-rendering="crispEdges" font-family="Monotype Corsiva" > HELLO </text>
</svg>
Variant with value and operator = "xor"
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="400" height="200" viewBox="0 0 400 200" >
<defs>
<filter id="f">
<feGaussianBlur in="SourceGraphic" stdDeviation="1" result="blur" >
<animate attributeName="stdDeviation" begin="0s" dur="8s" repeatCount="indefinite" values="1;6;12;12;6;1;1" />
</feGaussianBlur>
<feColorMatrix in="blur" type="matrix"
values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 29 -1"
result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="xor"/>
</filter>
</defs>
<text filter="url(#f)" x="35" y="120" font-size="100px" fill="#111111" shape-rendering="crispEdges" font-family="Monotype Corsiva" > HELLO </text>
</svg>
Text elements provided as input to a filter will be anti-aliased before they're rasterized, and the filter preserves the anti-aliasing unless you're doing something to the alpha channel.
In this case, you ARE doing something to the alpha channel. That feColorMatrix filter is multiplying the alpha channel by 15 and then subtracting 8. This has the effect of converting any pixels that have less than 8/15th opacity to transparent - which strips most of the anti-aliasing.
If you want to smooth out the edges a little, you can add another feGaussianBlur with a 0.5 or 1 unit stdDeviation to the end. There are other methods to add back the anti-aliasing but it really depends on what you're trying to do. Since the current filter doesn't do anything - I assume the intention is to animate something?
(Also - that feColorMatrix should have type='matrix' not mode='matrix' - mode is only used in feBlend.)
Update: may as well add the various techniques to smooth the edges.
Original
Original with the crispy filter
#2 with a small blur tagged on at the end
#2 with a small blur tagged on but clipped to a one pixel perimeter
#2 with a small blur, but the low opacity part of the blur clipped to zero
<svg width="1000px" height="1000px" >
<filter id="f1">
<feGaussianBlur in="SourceGraphic" stdDeviation="0" result="blur" />
<feColorMatrix
in="blur"
mode="matrix"
values="1 0 0 0 0
0 1 0 0 0
1 0 1 0 0
0 0 0 15 -8"
result="goo"
/>
<feComposite in="SourceGraphic" in2="goo" operator="atop" />
</filter>
<filter id="f2">
<feGaussianBlur in="SourceGraphic" stdDeviation="0" result="blur" />
<feColorMatrix
in="blur"
mode="matrix"
values="1 0 0 0 0
0 1 0 0 0
1 0 1 0 0
0 0 0 15 -8"
result="goo"
/>
<feComposite in="SourceGraphic" in2="goo" operator="atop" />
<feGaussianBlur stdDeviation="1"/>
</filter>
<filter id="f3">
<feGaussianBlur in="SourceGraphic" stdDeviation="0" result="blur" />
<feColorMatrix
in="blur"
mode="matrix"
values="1 0 0 0 0
0 1 0 0 0
1 0 1 0 0
0 0 0 15 -8"
result="goo"
/>
<feComposite in="SourceGraphic" in2="goo" operator="atop" result="pre-final"/>
<feMorphology operator="dilate" radius="1" result="base"/>
<feGaussianBlur in="pre-final" stdDeviation="1" />
<feComposite in2="base" operator="in" />
</filter>
<filter id="f4">
<feGaussianBlur in="SourceGraphic" stdDeviation="0" result="blur" />
<feColorMatrix
in="blur"
mode="matrix"
values="1 0 0 0 0
0 1 0 0 0
1 0 1 0 0
0 0 0 15 -8"
result="goo"
/>
<feComposite in="SourceGraphic" in2="goo" operator="atop" result="pre-final"/>
<feGaussianBlur stdDeviation="1"/>
<feComponentTransfer>
<feFuncA type="table" tableValues="0 0 .7 .8 .9 1"/>
</feComponentTransfer>
</filter>
<text x="50" y="150" style="font-size: 160; font-weight: bold;">FILTERED </text>
<text filter="url(#f1)" x="50" y="300" style="font-size: 160; font-weight: bold;">FILTERED </text>
<text filter="url(#f2)" x="50" y="450" style="font-size: 160; font-weight: bold;">FILTERED </text>
<text filter="url(#f3)" x="50" y="600" style="font-size: 160; font-weight: bold;">FILTERED </text>
<text filter="url(#f4)" x="50" y="750" style="font-size: 160; font-weight: bold;">FILTERED </text>
</svg>

SVG element pixelated on retina only if filters applied

An SVG path element becomes unexpectedly pixelated on retina screens if I apply a filter to it. Without the filter, it looks nice and smooth.
I'm using a gaussian blur and a color matrix:
<filter id="svg-filter-rounded-corners" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="3" />
<feColorMatrix mode="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 -25" />
</filter>
Here's a reproducible example. The circle on the left has the filter, the circle on the right does not.
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="200" viewBox="0 0 400 200">
<defs>
<filter id="filter" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="3" />
<feColorMatrix mode="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 -25" />
</filter>
</defs>
<circle filter="url(#filter)" cx="100" cy="100" r="90" fill="none" stroke="#221C35" stroke-width="10" />
<circle cx="300" cy="100" r="90" fill="none" stroke="#221C35" stroke-width="10" />
</svg>
This is occurring in both Chrome and Firefox, on MacOS.
Is there anything I can do to keep the path smooth even with the filters applied?
This is crispy even on Chrome/Windows. And the issue is that the values you're using for your feColorMatrix are too large. It's nuking the anti-aliasing completely. Try:
<feColorMatrix mode="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 -4" />
Which gives a more reasonable result. If you don't like that result, you could try a more detailed manipulation of opacity using feComponentTransfer instead of the feColorMatrix.
<feComponentTransfer>
<feFuncA type="table" tableValues = "0 0 0 0 0.5 1 1 1 1 1 1 1 1 1 1 1"/>
</feComponentTransfer>

Create a "mask" with text in SVG

I'm currently trying to make a comment icon like below in svg, but with the space around the text as a cut hole in the speech bubble (not like the icon on the bottom).
I want to have a <text> element because I generate the svg dynamically with react.
Does someone know if it is possible ?
Thanks
This filter uses a "green-screen" technique: you color the parts of your content that you want to discriminate among in separate primary colors - then use a color matrix to generate separate nodes containing just the content of each particular color. After you process the contents - at the end you use another color matrix to recolor the content into your final (single) desired color.
<svg width='400px' height='400px' viewBox='0 0 258 229' >
<defs>
<filter id="cut-out">
<feColorMatrix type="matrix" values="0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
-1 0 0 1 0"
result="just-blue"/>
<feColorMatrix type="matrix" values="1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 -1 1 0"
in="SourceGraphic" result="just-red"/>
<feMorphology in="just-blue" operator="dilate" radius="3"/>
<feComposite operator="out" in="just-red"/>
<feComposite operator="over" in2="just-blue"/>
<feColorMatrix type="matrix" values="0 0 0 0 .33
0 0 0 0 .33
0 0 0 0 .33
0 0 0 1 0"/>
</filter>
</defs>
<g filter="url(#cut-out">
<circle r="50" fill="red" cx="100" cy="100"/>
<text x="110" y="140" stroke="none" fill="blue" font-size="70">3</text>
</g>
</svg>

Resources