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>
Related
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>
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>
I have a fairly simple setup where I want to alter the color of the svg image by using an svg filter:
<svg style="height: 0;">
<filter id="hover" color-interpolation-filters="sRGB"
x="0" y="0" height="100%" width="100%">
<feColorMatrix type="matrix"
values="
0 0 0 0 0
0 0 0 0 0.68
0 0 0 0 0.94
0 0 0 1 0
"
/>
</filter>
</svg>
<img style="-webkit-filter: url('#hover'); filter: url('#hover');"
src="https://upload.wikimedia.org/wikipedia/commons/8/81/Wikimedia-logo.svg" alt="" />
Please see the attached codepen for details.
It's working in firefox and chrome, but I can't seem to find the problem in safari. According to caniuse, support should be ok.
So, this is going to seem silly - but it's the initial linebreak in your filter that's throwing it off. Correcting it to:
<feColorMatrix type="matrix"
values="0 0 0 0 0
0 0 0 0 0.68
0 0 0 0 0.94
0 0 0 1 0
"
/>
... works perfectly. (Incidentally, at one point, IE couldn't handle linebreaks in the values array in any position - you had to put them all on one line.)
At first glance I thought this would be pretty straight forward. Google found this with the following bit of code, but it's not a real sobel filter.
<filter id="edge">
<feColorMatrix type="luminanceToAlpha" />
<feConvolveMatrix order="3" kernelMatrix="-1 -2 -1 0 0 0 1 2 1" />
<feConvolveMatrix order="3" kernelMatrix="-1 -2 -1 0 0 0 1 2 1" />
</filter>
Following the wikipedia page I would need a way to find the distances between two feConvolveMatrix results. I can square and add them by compositing, but there doesn't seem to be any way to get a square root operator. Is it possible?
I've added my current solution below but it doesn't quite match the reference.
That sample code is wrong. Here is a conventional Sobel using convolution. It separates out the channels and converts them to alpha, runs edge detection, recolors them back to RGB and adds the channels back together. To get to the exact reference result, it looks like they add thresholding - which can you can do using feComponentTransfer.
<svg width="600px" height="800px" >
<defs>
<filter id="sobel" x="0%" y="0%" width="100%" height="100%">
<!-- convert source image to luminance map-->
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
1 0 0 0 0" result="RChan" />
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
0 1 0 0 0" result="GChan" />
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
0 0 1 0 0" result="BChan" />
<!-- sobel edge detection-->
<feConvolveMatrix in="RChan" order="3" kernelMatrix="-1 -2 -1
0 0 0
1 2 1 "
result="Rhor" />
<feConvolveMatrix in="RChan" order="3" kernelMatrix="-1 0 1
-2 0 2
-1 0 1" result="Rver" />
<feComposite operator="arithmetic" k2="1" k3="1" in="Rhor" in2="Rver" />
<feColorMatrix type="matrix" values="0 0 0 1 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 1" result="rededge"/>
<feConvolveMatrix in="GChan" order="3" kernelMatrix="-1 -2 -1
0 0 0
1 2 1"
result="Ghor" />
<feConvolveMatrix in="GChan" order="3" kernelMatrix="-1 0 1
-2 0 2
-1 0 1" result="Gver" />
<feComposite operator="arithmetic" k2="1" k3="1" in="Ghor" in2="Gver" />
<feColorMatrix type="matrix" values="0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
0 0 0 0 1" result="greenedge"/>
<feConvolveMatrix in="BChan" order="3" kernelMatrix="-1 -2 -1
0 0 0
1 2 1 " result="Bhor" />
<feConvolveMatrix in="BChan" order="3" kernelMatrix="-1 0 1
-2 0 2
-1 0 1" result="Bver" />
<feComposite operator="arithmetic" k2="1" k3="1" in="Bhor" in2="Bver"/>
<feColorMatrix type="matrix" values="0 0 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 1" result="blueedge"/>
<feComposite operator="arithmetic" in="blueedge" in2="rededge" k2="1" k3="1"/>
<feComposite operator="arithmetic" in2="greenedge" k2="1" k3="1" result="finaledges"/>
<feFlood flood-color="black" result="black"/>
<feComposite operator="over" in="finaledges"/>
</filter>
</defs>
<image width="400" height="300" preserveAspectRatio="xMinYMin meet" xlink:href="http://www.roborealm.com/help/Sobel_src.jpg"/>
<image filter="url(#sobel)" y="400" width="400" height="300" xlink:href="http://www.roborealm.com/help/Sobel_src.jpg"/>
</svg>
feDiffuseLighting actually computes a sobel filter to generate a normal. I've thrown the following together, which extracts RGB into three white images each with R, G and B as alpha for the heightmap. The z component of the normal (which is 1 - sqrt(dx^2 + dy^2)) is then extracted with a directional light positioned above the image. Finally it's inverted (to obtain just sqrt(dx^2 + dy^2)) and all three channels are combined.
I'm not too sure about color-interpolation-filters="sRGB" the images is incredibly dark so I've set surfaceScale="8.0" to give higher variation in the deltas. It still doesn't look quite like the reference but it's close. Also, for whatever reason the filter expands outwards to cover other parts of the HTML (EDIT: see this).
Test images from this page:
.sobelme {
-webkit-filter: url('#sobel');
-moz-filter: url('#sobel');
-ms-filter: url('#sobel');
-o-filter: url('#sobel');
filter: url('#sobel');
}
<img class="sobelme" src="http://i.stack.imgur.com/sld5Y.png" />
<img src="http://i.stack.imgur.com/wq077.png" />
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="0">
<filter id="sobel" color-interpolation-filters="sRGB">
<feColorMatrix type="matrix" in="SourceGraphic" result="RA" values="0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
1 0 0 0 0"></feColorMatrix>
<feColorMatrix type="matrix" in="SourceGraphic" result="GA" values="0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
0 1 0 0 0"></feColorMatrix>
<feColorMatrix type="matrix" in="SourceGraphic" result="BA" values="0 0 0 0 1
0 0 0 0 1
0 0 0 0 1
0 0 1 0 0"></feColorMatrix>
<feDiffuseLighting in="RA" result="R" surfaceScale="8.0">
<feDistantLight elevation="90"></feDistantLight>
</feDiffuseLighting>
<feDiffuseLighting in="GA" result="G" surfaceScale="8.0">
<feDistantLight elevation="90"></feDistantLight>
</feDiffuseLighting>
<feDiffuseLighting in="BA" result="B" surfaceScale="8.0">
<feDistantLight elevation="90"></feDistantLight>
</feDiffuseLighting>
<feColorMatrix type="matrix" in="R" result="RS" values="-1 0 0 0 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 1"></feColorMatrix>
<feColorMatrix type="matrix" in="G" result="GS" values="0 0 0 0 0
0 -1 0 0 1
0 0 0 0 0
0 0 0 0 1"></feColorMatrix>
<feColorMatrix type="matrix" in="B" result="BS" values="0 0 0 0 0
0 0 0 0 0
0 0 -1 0 1
0 0 0 0 1"></feColorMatrix>
<feComposite in="RS" in2="GS" result="RSGS" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"></feComposite>
<feComposite in="RSGS" in2="BS" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"></feComposite>
</filter>
</svg>
UPDATE:
The test image is an approximation which ignores the distance between horizontal and vertical deltas and simply sums them. The Sobel filter for the normal calculation with the above feDiffuseLighting is normalized, which is why the scale by 8 is needed. Simply adding the absolute values of the horizontal and vertical deltas, without the sqrt() similarly to #MichaelMullany's answer, can be achieved as follows. An advantage is the annoying expansion of the filter outside the borders doesn't happen. color-interpolation-filters is necessary otherwise a gamma is applied, giving a strange result. It still doesn't quite match the test image but it's closer and simpler.
.sobelme {
-webkit-filter: url('#sobel');
-moz-filter: url('#sobel');
-ms-filter: url('#sobel');
-o-filter: url('#sobel');
filter: url('#sobel');
}
<img class="sobelme" src="http://i.stack.imgur.com/sld5Y.png" />
<img src="http://i.stack.imgur.com/wq077.png" />
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="0">
<filter id="sobel" color-interpolation-filters="sRGB">
<feConvolveMatrix in="SourceGraphic" order="3" preserveAlpha="true" kernelMatrix="-1 -2 -1
0 0 0
1 2 1 " result="VP" />
<feConvolveMatrix in="SourceGraphic" order="3" preserveAlpha="true" kernelMatrix="1 2 1
0 0 0
-1 -2 -1 " result="VN" />
<feConvolveMatrix in="SourceGraphic" order="3" preserveAlpha="true" kernelMatrix="-1 0 1
-2 0 2
-1 0 1 " result="HP" />
<feConvolveMatrix in="SourceGraphic" order="3" preserveAlpha="true" kernelMatrix="1 0 -1
2 0 -2
1 0 -1 " result="HN" />
<feComposite operator="arithmetic" in="VN" in2="VP" k2="1" k3="1" result="V" />
<feComposite operator="arithmetic" in="HN" in2="HP" k2="1" k3="1" result="H" />
<!-- <feComposite operator="arithmetic" in="V" in2="H" k2="1" k3="1" /> -->
<feBlend mode="lighten" in="H" in2="V" />
</filter>
</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>