Illustrator - "real" inner shadow to SVG object - svg

Wanted: An inset shadow (NOT inner glow) for a complex svg path, supporting following options:
shadow/light direction
shadow size
blur amount
opacity
Example Pic: Inset Shadow for SVG-Paths (SVG Effect)

select the svg object, open appearance toolbar, use this icon at the bottom to add svg-filter
use "+" to add a new filter and copy following code
<filter id="inset-shadow">
<feOffset dx="25" dy="25"></feOffset>
<feGaussianBlur result="offset-blur" stdDeviation="10"></feGaussianBlur>
<feComposite in="SourceGraphic" in2="offset-blur" operator="out" result="inverse"></feComposite>
<feFlood flood-color="black" flood-opacity=".75" result="color"></feFlood>
<feComposite in="color" in2="inverse" operator="in" result="shadow"></feComposite>
<feComposite in="shadow" in2="SourceGraphic" operator="over"></feComposite>
</filter>
dx="25" dy="25": shadow width
stdDeviation="10": blur width
flood-opacity=".75": opacity

Related

Creating inner shadow in svg

i'm new to svg and am trying to create inner shadow kind of similiar to the attached pic. I've tried the other stack-overflow answers but the shadow doesn't seems to be as strong as the png attached. Can the experts suggest any possible way of achieving the same?
That doesn't look like a normal inset shadow - the opacity is too high near the border. So you'll have to do some fancy filtering to duplicate it. Here's something that will work for any shape:
<svg width="600px" height="600px">
<defs>
<filter id="strong-inner">
<feFlood flood-color="red"/>
<!-- This next operation subtracts the original shape from the red color
field filling the filter region - which will give you a big color border
surrounding the original shape -->
<feComposite operator="out" in2="SourceGraphic" />
<!-- Next we want to expand the red border so it overlaps the space of the
original shape - the radius 4 below will expand it by 4 pixels -->
<feMorphology operator="dilate" radius="4"/>
<feGaussianBlur stdDeviation="5" />
<!-- After blurring it, we want to select just the parts of the blurred,
expanded border that overlap the original shape - which we can do by using
the 'atop' operator -->
<feComposite operator="atop" in2="SourceGraphic"/>
</filter>
</defs>
<rect x="10" y="10" width="500" height="500" fill="rgb(50, 0 , 200)" filter="url(#strong-inner)"/>
</svg>
We can use box-shadow with inset option.
<svg style="background: rgb(51,54,148); width: 439px; height: 419px; box-shadow: 0 0 15px 6px inset rgba(255,0,96,0.8)"></svg>

How to apply feBlend and preserve source alpha

I'm trying to modify colors of an image by applying feFlood and feBlend to it in "lighten" and "darken" modes. How do I preserve the alpha channel?
<svg>
<filter id="filter">
<feFlood result="flood" flood-color="blue" />
<feBlend in="SourceGraphic" in2="flood" mode="lighten" />
</filter>
<image filter="url(#filter)" href="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" />
</svg>
https://jsfiddle.net/utqghr0o/
The way lighten works is that it takes the maximum colour value from each channel of each of the two inputs (pre-multiplied with the alpha). So if a pixel has zero opacity, it will not ever count as the maximum colour for any channel, and the value from the other input will be used.
What you need to do is first mask the flood with the alpha from the source image ("SourceAlpha"), then blend the masked flood with the original image.
<svg width="544" height="184">
<filter id="filter">
<feFlood result="flood" flood-color="blue" />
<feComposite in="flood" in2="SourceAlpha" operator="atop" result="maskedflood"/>
<feBlend in="SourceGraphic" in2="maskedflood" mode="lighten" />
</filter>
<image filter="url(#filter)" width="544" height="184" href="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" />
</svg>
I think Paul's answer is close but not exactly correct.
The feBlend formula is:
Opacity of Final Pixel = 1 - (1- Opacity of Image A Pixel)*(1- Opacity of Image B Pixel)
If you do the mask first and then the blend, the final opacity will be a bit off. For example for a pixel of 0.6 opacity in image A, you'll end up with a final pixel opacity = 1 - (.6 * .6) = .64
That's close to, but not the same as 0.6.
If you want to retain the exact opacity of Image A in the final image - you need to do the blending first and the masking second. That's assuming that you want the lighten to be done on the pre-multiplied, "100%-opaque-equivalent" colors, which is normally the case.
<svg width="544" height="184">
<filter id="filter">
<feFlood result="flood" flood-color="blue" />
<feBlend in="SourceGraphic" in2="flood" mode="lighten" result="blend"/>
<feComposite in="blend" in2="SourceAlpha" operator="atop" result="maskedflood"/>
</filter>
<image filter="url(#filter)" width="544" height="184" href="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" />
</svg>

SVG Filter with a mask

There is a filter
<filter id="filter">
<feGaussianBlur stdDeviation="4">
<feColorMatrix type="matrix" values="">
</filter>
applied to image
<image filter="url('#filter')">
I have a certain shape:
<polygon points="">
How can I use the polygon as a mask where the filter is not applied?
You could also apply the filter to the polygon and then use feImage to import your image into the filter. Using feComposite "in" will do the masking.
<svg height="210" width="500">
<defs>
<filter id="cutout" x="-300%" y="-300%" height="700%" width="700%">
<feImage result="photo" xlink:href="http://upload.wikimedia.org/wikipedia/commons/thumb/2/2d/%D0%9D%D1%96%D0%B6%D0%BD%D0%B8%D0%B9_%D1%80%D0%B0%D0%BD%D0%BA%D0%BE%D0%B2%D0%B8%D0%B9_%D1%81%D0%B2%D1%96%D1%82%D0%BB%D0%BE.jpg/1280px-%D0%9D%D1%96%D0%B6%D0%BD%D0%B8%D0%B9_%D1%80%D0%B0%D0%BD%D0%BA%D0%BE%D0%B2%D0%B8%D0%B9_%D1%81%D0%B2%D1%96%D1%82%D0%BB%D0%BE.jpg" preserveAspectRatio="xMidYMid meet"/>
<feGaussianBlur stdDeviation="10" result="blurphoto"/>
<feComposite operator="in" in="photo" in2="SourceGraphic" result="photomask"/>
<feComposite operator="over" in2="blurphoto" in="photomask"/>
</filter>
</defs>
<polygon filter="url(#cutout)" points="20,10 250,190 200,30 160,34 160,210" style="fill:lime;stroke:purple;stroke-width:1" />
</svg>
Use two <image> elements at the same location.
The first image would have a filter (as you have it now).
The second image would not have a filter, instead it would have a clip.
The clipPath used by the second image will need to have the polygon as its contents.
If you really want one image, you could probably merge the images using canvas drawImage and then write out the composite image to a new <image> element.

Apply SVG filter to "fill" only

How do I apply an SVG filter on an SVG element, but not on its stroke?
Let's say I have this SVG filter (it puts the red component to 100%):
<filter id="testStroke">
<feComponentTransfer>
<feFuncR type="linear" slope="0" intercept="1"/>
</feComponentTransfer>
</filter>
If I apply this filter on that text node:
<text x="450" y="210" fill="black" stroke="blue" filter="url('#testStroke')">
Result
</text>
Then the filled part (originally black) turns red (because of the filter), and the blue stroke turns purple (same reason).
I would like the stroke to stay blue (not filtered), but the fill to turn red (filtered).
I'm not looking for the "don't stroke the shape, apply the filter on it and create a clone of that shape to apply the stroke on".
Is there a way to apply the filter only on the filled part on a shape, and not on its stroke?
There is no configuration or attribute to select the fill directly, but you can use a "green-screen" technique to select out the stroke, filter the fill and then reapply the stroke. You have to know the colors of the stroke and fill ahead of time, which is a downside (because the pseudo inputs for doing this are not supported in Chrome/Safari (although they are in Firefox and IE10)). So here is a working example:
<filter id="testStroke">
<feComponentTransfer in="SourceGraphic" result="recolored">
<feFuncR type="linear" slope="0" intercept="1"/>
</feComponentTransfer>
<!-- We're using the fact that the black fill has zero luminance to create a selection mask for the stroke -->
<feColorMatrix in="SourceGraphic" type="luminanceToAlpha" result="lumMask"/>
<feComponentTransfer in="lumMask" result="lumMaskCeil">
<!-- a blue fill doesn't have a high luminance, so we're going to dial it way up using a gamma transform with a high exponent-->
<feFuncA type="gamma" exponent=".01"/>
</feComponentTransfer>
<!-- this selects just the part of the input image that overlaps with our stroke mask-->
<feComposite operator="in" in="SourceGraphic" in2="lumMaskCeil" result="stroke"/>
<!-- and composite it over our recolored content from the original filter-->
<feComposite operator="over" in="stroke" in2="recolored"/>
</filter>

SVG filter feGaussianBlur needs boosting

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.

Resources