SVG: color of the shadow - colors

I want to write a simple rectangle with a red shadow in SVG.
I have a simple filter:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1012" height="400">
<title>svg arrow with dropshadow</title>
<desc>An svg example of an arrow shape with a dropshadow filter applied. The dropshadow filter effect uses feGaussianBlur, feOffset and feMerge.</desc>
<defs>
<filter id="dropshadow" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feComponentTransfer in="SourceAlpha">
<feFuncR type="discrete" tableValues="1"/>
<feFuncG type="discrete" tableValues="0"/>
<feFuncB type="discrete" tableValues="0"/>
</feComponentTransfer>
<feGaussianBlur stdDeviation="2"/>
<feOffset dx="0" dy="0" result="shadow"/>
<feComposite in="SourceGraphic" in2="shadow" operator="over"/>
</filter>
</defs>
<rect rx="2" ry="2" fill="rgb(255,255,255)" x="5.25" y="5.25" width="141" height="50" fill-opacity="0.85" filter="url(#dropshadow)">
</svg>
Why in this example shadow color is not red? Where is my bad?

For those looking for a general solution, this worked for me inside a element:
<feGaussianBlur in="SourceAlpha" stdDeviation="1.7" result="blur"/>
<feOffset in="blur" dx="3" dy="3" result="offsetBlur"/>
<feFlood flood-color="#3D4574" flood-opacity="0.5" result="offsetColor"/>
<feComposite in="offsetColor" in2="offsetBlur" operator="in" result="offsetBlur"/>

You have provided invalid SVG - you need to close your <rect> element.
Your example (fixed) shows a red shadow for me in Chrome. Here's what this URL looks like for me with Chrome v15:
What OS/browser/version are you seeing different results with?
Edit: In Firefox v7 I see all greyscale, and in Safari v5 I don't see the shadow effect at all. Your answer, most likely then, is simply that you're testing in a browser/version with incomplete support of the SVG filter specification.

Related

Elliptical light source using SVG filters

I am trying to apply a Vignette effect on images with SVG filters. I am trying to implement this with the <fePointLight> primitive, but I find this a bit limited in that it is always has a circular shape. Is it possible to change the width such that the lighting effect takes on a wide elliptical shape? This is currently the filter I am using:
<filter id="vignette">
<feFlood id="flood-5" result="blackfield-6" x="0%" y="0%" width="100%" height="100%" flood-color="#000000" flood-opacity="1"/>
<feSpecularLighting id="specular-5" result="Spotlight-6" lighting-color="#FFFFFF" surfaceScale="1" specularConstant="1" specularExponent="100">
<fePointLight id="pointlight-5" x="720" y="450" z="1200"/>
</feSpecularLighting>
<feBlend id="svg-7" result="A-6" in="blackfield-6" in2="Spotlight-6" mode="lighten"/>
<feBlend id="blend-5" result="B-6" in="A-6" in2="SourceGraphic" mode="multiply"/>
</filter>
I am aware that it is possible to do this with a radial gradient effect on a separate shape, but I have a requirement that it must be done purely using SVG filters.
The values of the x=350 and y=240 attributes of the fePointLight filter are chosen so that the point is in the center of the image.
Different values for the z attribute of the fePointLight filter render the light source at different depths in relation to the drawing. The nearest position corresponds to the largest size.
Please watch in full screen
Hover over image
#img {
width:700px;
height:481px;
}
#img:hover {
filter:url(#spotlight);
}
<img id="img" src="https://i.stack.imgur.com/mBuDo.jpg" >
<svg width="700" height="481" viewBox="0 0 700 481" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="spotlight">
<feSpecularLighting result="spotlight" specularConstant="3.5"
specularExponent="70" lighting-color="grey">
<fePointLight x="350" y="240" z="520"/>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="spotlight" operator="in"/>
</filter>
</defs>
</svg>
Other image
#img {
width:700px;
height:481px;
}
#img:hover {
filter:url(#spotlight);
}
<img id="img" src="https://i.stack.imgur.com/GlhkD.jpg" >
<svg width="700" height="481" viewBox="0 0 700 481" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="spotlight">
<feSpecularLighting result="spotlight" specularConstant="3.5"
specularExponent="70" lighting-color="grey">
<fePointLight x="350" y="240" z="520"/>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="spotlight" operator="in"/>
</filter>
</defs>
If you want that sort of effect (elliptical light), you probably want to be using a spotlight rather than a point light.
If you offset the light position to one side and shine the cone down at a shallow-ish angle, you will get an elliptical spot.
<svg width="600" height="529">
<defs>
<filter id="spotlight">
<feSpecularLighting result="spotlight" specularConstant="1.5"
specularExponent="4" lighting-color="#FFF">
<feSpotLight x="-200" y="265" z="400" limitingConeAngle="10" pointsAtX="300" pointsAtY="265" />
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="spotlight" operator="out" k1="0" k2="1" k3="1" k4="0"/>
</filter>
</defs>
<rect x="0" y="0" width="600" height="529" style="fill: skyblue; filter:url(#spotlight);"/>
</svg>
Note that the lighting filter components can be unreliable to use. Each browser has differences in interpretation of the standard. Not to mention some bugs.
A point in case is the above example, which looks different in Firefox and Chrome.
But good luck with your project.

SVG text edges change color when scaling

I've created an SVG filter and applied it to some text. When I scale the text smaller by resizing the browser window, some of the edges of the text have a colored line down one side.
<svg
class="tstx" viewBox="0 0 160 160"
height="160" width="160"
style="width: 100%; height: 100%">
<defs>
<filter id="innershadow" x0="-50%" y0="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/>
<feOffset dy="3" dx="3"/>
<feComposite in2="SourceAlpha" operator="arithmetic"
k2="-1" k3="1" result="shadowDiff"/>
<feFlood flood-color="grey" flood-opacity="1"/>
<feComposite in2="shadowDiff" operator="in"/>
<feComposite in2="SourceGraphic" operator="over"/>
</filter>
</defs>
<g
font-family="Verdana" font-size="80" font-weight="bold"
stroke="none" fill="#fff" filter="url(#innershadow)">
<text x="10" y="70">A</text>
<text x="80" y="70">B</text>
</g>
</svg>
How can I fix this?
Codepen Example
Move the middle margin right to scale text.
EDIT: It looks like I may have fixed the problem - I just don't know why it worked or if it will cause problems later on. I removed the following:
<feComposite in2="SourceGraphic" operator="over"/>
And the lines disappeared. Is anyone able to explain why?

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)" />

How to get "crispEdges" for SVG text?

Svg shapes other than text are affected by the shape-rendering attribute which can be set to the crispEdges value (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering). This value seems to turn anti-aliasing off.
But text is only affected by text-rendering. However, this does not provide the crispEdges value (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-rendering). Why? Is there another way to get non-anti-alias?
For really crisp edges, you can use a filter to posterize your text.
<svg width="400px" height="400px">
<defs>
<filter id="crispify">
<feComponentTransfer>
<feFuncA type="discrete" tableValues="0 1"/>
</feComponentTransfer>
</filter>
</defs>
<text filter="url(#crispify)" font-size="60" y="60" >Some crispy text</text>
</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