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.
Imagine we have a long list of instances (as an example, see just two such instances (INSTANCE1 and INSTANCE2) below) which all depend on some pre-defined #DEFINED_RECTANGLE_WHITE which does not contain stroke information in its definition.
As you can see, some of the instances will be scaled (see e.g. scale(1 2)). I am wondering what would be the best way of now stroking all of these instances (all should have same stroke-width, I do not want the strokes to be wider in any dimension on the scaled objects).
<use id="INSTANCE1"
xlink:href="#DEFINED_RECTANGLE_WHITE"
transform="rotate(90, 1, 1) translate(10,-400) scale(1 2)">
</use>
<use id="INSTANCE2"
xlink:href="#DEFINED_RECTANGLE_WHITE"
transform="translate(10,140)">
</use>
How to do this without SVG1.2 features?
Could you use a filter to create an outline effect? You would have to enclose your use elements in a group or another svg and apply the filter to that.
Also, the dilate operator can have undesired results, like the bevel effect in the last rotated rectangle.
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 100 100">
<defs>
<rect id="rectangle" width="10" height="10" fill="rgb(200,220,120)"/>
<filter id="outline">
<feMorphology operator="dilate" radius="4" result="result1"/>
<feFlood flood-color="rgb(51,51,51)" result="result2"/>
<feComposite in="result2" in2="result1" operator="in" result="result3"/>
<feComposite in="SourceGraphic" in2="result3"/>
</filter>
</defs>
<g filter="url(#outline)">
<use href="#rectangle" transform="translate(50,10) scale(4 1) rotate(90,1,1)"/>
<use href="#rectangle" transform="translate(40,30)"/>
<use href="#rectangle" transform="translate(20,50) scale(6 0.5)"/>
<use href="#rectangle" transform="translate(60,70) rotate(45,1,1)"/>
</g>
</svg>
edit : oh snap! #Kaiido posted exactly the same answer while I was writing mine. Sorry for stealing your thunder =(
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)" />
I would like to use an image to control the alpha channel of a fill in SVG.
I can't figure out the right way to combine SourceGraphic with the alpha. Here is what I have right now:
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 300 300">
<defs>
<filter id="FILTER_pencil" primitiveUnits="userSpaceOnUse" filterUnits="objectBoundingBox" width="100%" height="100%">
<feImage result="result1" width="128" height="128" xlink:href="http://lightartpixel.com/FILTER_pencil.png"/>
<feColorMatrix type="luminanceToAlpha" result="alpha" in="result1"/>
<feComposite operator="atop" in="alpha" in2="SourceGraphic"></feComposite>
</filter>
</defs>
<rect fill="#5d496a" stroke="#5d496a" filter="url(#FILTER_pencil)" width="100" height="100"/>
</svg>
Here is a jsfiddle that shows the current output. Which seems to be combining the luminance with the fill color.
You don't want to use atop, that renders both the black shape with variable opacity that you got from the luminanceToAlpha as well as the source graphic. Instead, you want to use the "in" operator, which only renders the source graphic, but uses the alpha values from the luminanceToAlpha as alpha. You also need to reverse the order of your "ins". This gets you what you want.
<feComposite operator="in" in2="alpha" in="SourceGraphic"></feComposite>
I want to have a black text with a white outer glow in order to be readable on a colored map. This is what I used to do:
<defs>
<filter id="label-glow">
<feGaussianBlur stdDeviation="1" />
</filter>
</defs>
<text stroke="white" stroke-width="5" filter="url(#label-glow)">Harald's Repose</text>
<text>Harald's Repose</text>
I'd like to avoid duplicating the text element, so I decided to use feFlood to create a white rectangle, feComposite to create a white copy of the text, feGaussianBlur to create the blur, and then another feComposite to add the original text on top of it all. Unfortunately, the resulting outer glow is very weak. I found that repeating the feComposite a few times helps. I'm sure there's a better solution. What am I doing wrong?
<defs>
<filter id="label-glow">
<feFlood flood-color="white"/>
<feComposite in2="SourceGraphic" operator="in"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite operator="over"/>
<feComposite operator="over"/>
<feComposite operator="over"/>
<feComposite operator="over"/>
<feComposite in="SourceGraphic"/>
</filter>
</defs>
<text filter="url(#label-glow)">Harald's Repose</text>
A slightly more elegant way is to dial up the opacity on your glow using a feComponentTransfer on the alpha channel.
<filter id="label-glow">
<feFlood flood-color="white"/>
<feComposite in2="SourceGraphic" operator="in"/>
<feGaussianBlur stdDeviation="2"/>
<feComponentTransfer>
<feFuncA type="gamma" exponent=".5" amplitude="2"/>
</feComponentTransfer>
<feComposite in="SourceGraphic"/>
</filter>
You can adjust the average intensity of the white by changing amplitude and you can adjust the intensity falloff by changing exponent.