Rectangle with looming border - svg

I want to create rectangle with smoothed border. Important part that size of it's solid part should be certain. To clarify I'll give an example:
I can achieve desired effect with Gaussian filter:
<svg id="svg-root" width="800" height="600"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="test-body-content">
<defs>
<filter id="blur" filterUnits="userSpaceOnUse">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
<feMerge>
<feMergeNode in="blur" />
</feMerge>
</filter>
</defs>
<rect x="50" y="50" width="200" height="100" fill="black" filter="url(#blur)"/>
</g>
</svg>
Result:
But it doesn't meet requirements because it is not fully solid within given dimensions (width="200" height="100"):
Also I thought about applying gradient perpendicular to stroke, but SVG doesn't support such thing.

As #ABFORCE wrote you can provide the width and height you want via the filter element.
For example:
<filter id="blur" filterUnits="objectBoundingBox"
x="0" y="0" width="100%" height="100%">
...
</filter>
Note that this means that above filter will be clipped to the boundingbox of the filtered element.
If you want the original shape in the filter output you could add another feMergeNode like this:
<svg id="svg-root" width="800" height="600"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="test-body-content">
<defs>
<filter id="blur" filterUnits="userSpaceOnUse">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<rect x="50" y="50" width="200" height="100" fill="black" filter="url(#blur)"/>
</g>
</svg>
Live example.

Related

Render beveled border on SVG rect

Is it possible to render a border of a SVG rect to emulate an outset?
with CSS?
with filters?
NB: It has to be a single scalable simple rect object, so I don't want to build it with paths / composite objects.
It's possible to do this with a filter. You do it by drawing a masking shape in the SVG and doing the stroking in the filter.
<svg width="600px" height="800px" color-interpolation-filters="sRGB">
<filter id="rect-and-stroke" x="0%" y="0%" width="100%" height="100%">
<feFlood flood-color="red" result="red-stroke"/>
<feFlood flood-color="orange" result="orange-stroke"/>
<feFlood x="10" y="10" width="180" height="80" flood-color="yellow" result="yellow-field"/>
<feComposite operator="in" in2="SourceGraphic" in="red-stroke" result="red-partial"/>
<feComposite operator="out" in2="SourceGraphic" in="orange-stroke" result="orange-partial"/>
<feMerge>
<feMergeNode in="red-partial" />
<feMergeNode in="orange-partial" />
<feMergeNode in="yellow-field" />
</feMerge>
</filter>
<path filter="url(#rect-and-stroke)" fill="black" d="M 0 0 L 10 10 180 80 200 100 0 100Z"/>
</svg>

SVG blur filter has hard borders

I have this code in which I want to add a feGaussianBlur to a <rect/> element:
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
<defs>
<filter id="f">
<feGaussianBlur in="SourceGraphic" stdDeviation="20"/>
</filter>
</defs>
<rect x="100" y="100" height="200" width="180" fill="green" filter="url(#f)"/>
</svg>
The output is rendered like this:
As you can see, that the sides are not softened. The sides have a hard border.
But, when I decrease the value of the stdDeviation, it works well. Here is the output if the value of stdDeviation is set to 10:
Why is it not working properly with a value greater than 10? And what can I do to achieve it?
Expand the filter region
x="-20%" y="-20%" width="150%" height="150%"
See Filter effects region
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
<defs>
<filter id="f" x="-20%" y="-20%" width="150%" height="150%">
<feGaussianBlur in="SourceGraphic" stdDeviation="20"/>
</filter>
</defs>
<rect x="100" y="100" height="200" width="180" fill="green" filter="url(#f)"/>
</svg>

Matching SVG fill pattern with repeated background image on containing element?

I am trying to create some ornate page dividers using SVGs with a fill pattern using the same image as the containing element's background image but I am having difficulty getting the SVG pattern to match the repeated background image of the containing element. I found a few similar questions on StackOverflow which mentioned using preserveAspectRatio but none of the solutions I've found are creating the desired effect.
Here's what my SVG code looks like:
<svg id="Layer_1" class="divider" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 150" >
<defs>
<pattern id="imgpattern" patternUnits="userSpaceOnUse" width="576" height="576" preserveAspectRatio="xMinYMin slice">
<image width="576" height="576" xlink:href="http://s12.postimg.org/730a258rx/pattern2.jpg"/>
</pattern>
<filter id="dropshadow" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="0" dy="2" result="offsetblur"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<path d="M-394.09,367.9V295.34l1400,0v70s-3.39.9-4.92,1.38c-56.68,17.79-114.85,25.72-174.22,26.17-36.9.27-73.6-2.7-110.25-6.28q-67.4-6.59-134.7-14.08c-49.65-5.51-99.28-8.74-149-1.64-35.12,5-68.54,15.05-99.24,33.08-6,3.53-12.09,7-18.13,10.48-8.94,5.18-17.93,5.51-27,.36-3.47-2-7.14-3.6-10.51-5.71-48.22-30.22-101-43.79-157.83-41.84-29.13,1-58.27,2.45-87.3,4.94-40.49,3.48-80.88,8.18-121.32,12.27-24.37,2.46-48.71,5.26-73.14,7a714.52,714.52,0,0,1-96.42.34,605.73,605.73,0,0,1-96.81-13.9C-368.07,374.88-394.09,367.9-394.09,367.9Z" transform="translate(394.09 -295.32)" stroke="none" fill="url(#imgpattern)" filter="url(#dropshadow)" />
</svg>
And here's a JSFiddle which recreates my issue. Notice how the background pattern of the SVG appears more stretched and because of that does not completely match the repeated background image of the container.
One option is just to move the pattern fill into the filter like so - although there is a small problem that your texture has a one pixel black border, so the tiling isn't perfect.
<filter id="dropshadowandfill" height="130%" >
<feImage x="0" y="0" width="575" height="575" xlink:href="http://s12.postimg.org/730a258rx/pattern2.jpg"></feImage>
<feTile/>
<feComposite operator="in" in2="SourceGraphic" result="filledOriginal"/>
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="0" dy="2" result="offsetblur"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="filledOriginal"/>
</feMerge>
</filter>
</defs>
<path d="M-394.09,367.9V295.34l1400,0v70s-3.39.9-4.92,1.38c-56.68,17.79-114.85,25.72-174.22,26.17-36.9.27-73.6-2.7-110.25-6.28q-67.4-6.59-134.7-14.08c-49.65-5.51-99.28-8.74-149-1.64-35.12,5-68.54,15.05-99.24,33.08-6,3.53-12.09,7-18.13,10.48-8.94,5.18-17.93,5.51-27,.36-3.47-2-7.14-3.6-10.51-5.71-48.22-30.22-101-43.79-157.83-41.84-29.13,1-58.27,2.45-87.3,4.94-40.49,3.48-80.88,8.18-121.32,12.27-24.37,2.46-48.71,5.26-73.14,7a714.52,714.52,0,0,1-96.42.34,605.73,605.73,0,0,1-96.81-13.9C-368.07,374.88-394.09,367.9-394.09,367.9Z" transform="translate(394.09 -295.32)" stroke="none" filter="url(#dropshadowandfill)" />

Apply texture tile tint to SVG

I'm trying to apply a texture tint to the SVG.
It's working almost fine but I need to make the texture as a tile for a better image quality
<filter id="composite" x="0" y="0" width="100%" height="100%">
<feImage result="sourceTwo" xlink:href="_link_" />
<feComposite in="SourceGraphic" in2="sourceTwo" operator="arithmetic" k1="1"/>
</filter>
How to replace feImage with a tile of the same image
jsFiddle
This is what the feTile primitive is for - but there is a regression bug in Chrome that clips the content - this is reported and a fix has been checked in (but still - buggy for now).
<svg width="500px" height="600px" viewBox="0 0 500 600">
<defs>
<filter id="composite" x="0%" y="0%" width="100%" height="100%">
<feImage result="sourceTwo" xlink:href="http://demo.prestalife.net/media/wood.jpg" width="34" height="34"/>
<feTile result="tiledImage"/>
<feComposite in="SourceGraphic" in2="tiledImage" operator="arithmetic" k1="1" k2="0" k3="0" k4="0"/>
</filter>
</defs>
<text x="0" y="20">Original image</text>
<image width="34" height="34" x="0" y="30" xlink:href="http://demo.prestalife.net/media/wood.jpg" />
<g filter="url(#composite)">
<rect fill="red" width="100%" height="100%" x="0" y="80" />
</g>
</svg>

Why does a filter break the half-pixel trick for crisp 1px strokes?

I'm using the "offset everything by half a pixel" trick discussed in the second answer to this question to get a crisp 1px stroke on a shape.
(There are rounded edges involved, so the shape-rendering: crispEdges solution isn't viable here -- it makes the curved parts of strokes look terrible.)
How come adding a filter (I'm using a gaussian blur + offset filter to implement a drop shadow) breaks the half-pixel offset hack?
You can play with the jsfiddle.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="f1" x="-20%" y="-20%" width="160%" height="160%">
<feOffset result="offOut" in="SourceAlpha" dx="10" dy="10" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="2" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<g transform="translate(5.5,5.5)">
<!-- This one has a blurry stroke -->
<rect width="50" height="50" rx="5" ry="5" stroke="black" stroke-width="1" fill="steelblue" filter="url(#f1)" />
<!-- This one has a crisp stroke -->
<rect x="150" width="50" height="50" rx="5" ry="5" stroke="black" stroke-width="1" fill="steelblue" />
</g>
</svg>
Apparently I can't post inline images as a new user, but you can this is an image of how the svg looks for me.
If you don't like the blurry edges, you can always experiment with adding an feComponentTransfer with feFuncA to manually manipulate the edge blur. Aka:
<filter id="fee" x="-20%" y="-20%" width="160%" height="160%">
<feComponentTransfer>
<feFuncA type="table" tableValues="0 0 1" />
</feComponentTransfer>
</filter>

Resources