Apply texture tile tint to SVG - 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>

Related

How do I stop svg GaussianBlur from being clipped? [duplicate]

Why does the grid in this SVG not fill the entire 256x256 space? No matter what size I change it to, about 15% of the grid is cut off, which appears to me to be arbitrary in the context of my code.
<svg width="256" height="256" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="grid" width="18.75" height="18.75" patternUnits="userSpaceOnUse">
<path d="M 18.75 0 L 0 0 0 18.75" fill="none" stroke="black" stroke-width="1"/>
</pattern>
<rect id="gridRect" width="100%" height="100%" fill="url(#grid)" />
<filter id="gridify" width="100%" height="100%" filterUnits = "userSpaceOnUse">
<feImage result="sourceTwo" xlink:href="#gridRect" />
<feComposite in="SourceGraphic" in2="sourceTwo" operator="in"/>
</filter>
</defs>
<g filter="url(#gridify)" >
<rect width="100%" height="100%" fill="url(#linGradient)" />
</g>
<rect width="100%" height="100%" fill="none" stroke="black" stroke-width="1"/>
</svg>
The SVG specification defaults filters to being 10% larger than the filtered object by default.
If ‘x’ or ‘y’ is not specified, the effect is as if a value of -10% were specified.
If ‘width’ or ‘height’ is not specified, the effect is as if a value of 120% were specified.
I imagine that's to stop lots of questions along the lines of "why is my Gaussian blur based drop-shadow filter cut off?"
So, looks like all I needed to do to fix it was add an x="0" and a y="0" to the filter. I don't understand why it is necessary though, as it does not make sense that it would default to "-15%".
<svg width="256" height="256" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="grid" width="18.75" height="18.75" patternUnits="userSpaceOnUse">
<path d="M 18.75 0 L 0 0 0 18.75" fill="none" stroke="black" stroke-width="1"/>
</pattern>
<rect id="gridRect" width="100%" height="100%" fill="url(#grid)" />
<filter id="gridify" x="0" y="0" width="100%" height="100%" filterUnits = "userSpaceOnUse">
<feImage result="sourceTwo" xlink:href="#gridRect" />
<feComposite in="SourceGraphic" in2="sourceTwo" operator="in"/>
</filter>
</defs>
<g filter="url(#gridify)" >
<rect width="100%" height="100%" fill="url(#linGradient)" />
</g>
<rect width="100%" height="100%" fill="none" stroke="black" stroke-width="1"/>
</svg>

Displacement map filter not working on rotated object

I am trying to make mirrored pattern, but when I add displacement filter, it seems it only works on first and fourth quandrant. Am I overlooking some beginner mistake or is this behavior expected?
<svg width="500px" height="500px">
<defs>
<clipPath id="clip">
<rect x="0" y="0" width="50%" height="50%"/>
</clipPath>
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" width="4" height="4" patternTransform="scale(20) rotate(0)">
<path d="M-1,1 l2,-2
M0,4 l4,-4
M3,5 l2,-2"
style="stroke:red; stroke-width:1" />
</pattern>
<symbol id="quarter">
<rect x="0" y="0" width="100%" height="100%" fill="url(#diagonalHatch)" clip-path="url(#clip)"/>
</symbol>
<filter id="noise" x="0%" y="0%" width="100%" height="100%">
<feTurbulence baseFrequency="0.02" numOctaves="3" result="noise" seed="3" />
<feDisplacementMap in="SourceGraphic" in2="noise" scale="8" />
</filter>
</defs>
<g filter="url(#noise)">
<use xlink:href="#quarter"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(90)"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(180)"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(270)"/>
</g>
</svg>
In your filter I've added xChannelSelector="R" for the feDisplacementMap. I'm using R for red since your shapes are red.
<filter id="noise" x="0%" y="0%" width="100%" height="100%">
<feTurbulence baseFrequency="0.02" numOctaves="3" result="noise" seed="3" />
<feDisplacementMap in="SourceGraphic" in2="noise" scale="8" xChannelSelector="R" />
</filter>
<svg width="500px" height="500px">
<defs>
<clipPath id="clip">
<rect x="0" y="0" width="50%" height="50%"/>
</clipPath>
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" width="4" height="4" patternTransform="scale(20) rotate(0)">
<path d="M-1,1 l2,-2
M0,4 l4,-4
M3,5 l2,-2"
style="stroke:red; stroke-width:1" />
</pattern>
<symbol id="quarter">
<rect x="0" y="0" width="100%" height="100%" fill="url(#diagonalHatch)" clip-path="url(#clip)"/>
</symbol>
<filter id="noise" x="0%" y="0%" width="100%" height="100%">
<feTurbulence baseFrequency="0.02" numOctaves="3" result="noise" seed="3" />
<feDisplacementMap in="SourceGraphic" in2="noise" scale="8" xChannelSelector="R" />
</filter>
</defs>
<g filter="url(#noise)">
<use xlink:href="#quarter"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(90)"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(180)"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(270)"/>
</g>
</svg>
Also I would have applied the filter to the <rect> inside <symbol> instead of applying it to the group.
You're just missing an xChannelSelector or yChannelSelector - one of which is required.
(Update - as you mention in the comment, when you leave this out, it defaults to using the alpha channel in both X and Y - so it will shift everything up and down the top/left bottom/right diagonal axis - so solid color diagonal lines with this orientation will only show distortions at their starting and finishing edges).
If you're not going to process the feTurbulence in some way after you generate it, then any one of the channels (RGBA) works as a displacement source - since Perlin noise is equally noisy in all four channels.
(You don't need to use the R channel because your shapes are red - that's backwards - the channel selector applies to your noise input, not your the shape you want to apply it to.)
<svg width="500px" height="500px">
<defs>
<clipPath id="clip">
<rect x="0" y="0" width="50%" height="50%"/>
</clipPath>
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" width="4" height="4" patternTransform="scale(20) rotate(0)">
<path d="M-1,1 l2,-2
M0,4 l4,-4
M3,5 l2,-2"
style="stroke:red; stroke-width:1" />
</pattern>
<symbol id="quarter">
<rect x="0" y="0" width="100%" height="100%" fill="url(#diagonalHatch)" clip-path="url(#clip)"/>
</symbol>
<filter id="noise" x="0%" y="0%" width="100%" height="100%">
<feTurbulence baseFrequency="0.02" numOctaves="3" result="noise" seed="3" />
<feDisplacementMap in="SourceGraphic" in2="noise" scale="8" xChannelSelector="R" yChannelSelector="G"/>
</filter>
</defs>
<g filter="url(#noise)">
<use xlink:href="#quarter"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(90)"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(180)"/>
<use xlink:href="#quarter" style="transform-origin: 50% 50%;" transform="rotate(270)"/>
</g>
</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>

Apply a texture to an image in SVG

I'm trying to apply a texture to an image
Original
Texture
Result (made with PHP GD)
But with SVG, the closest I got is this result
<svg preserveAspectRatio="none" width="500" height="500" viewBox="0 0 500 500">
<defs>
<filter id="texture">
<feImage href="https://i.imgur.com/pjWcnJs.jpg" result="texture-img"/>
<feBlend in="SourceGraphic" in2="texture-img" mode="multiply"/>
</filter>
</defs>
<g>
<g filter="url(#texture)">
<image x="0" y="0" href="https://i.imgur.com/oVEdsQt.png" opacity="1" width="500" height="500" />
</g>
</g>
</svg>
fiddle
Is there another way which won't texturize transparent pixels?
I found a solution which is to pass the texture through a composite filter which would crop it to the source image
<svg preserveAspectRatio="none" width="500" height="500" viewBox="0 0 500 500">
<defs>
<filter id="texture">
<feImage href="https://i.imgur.com/pjWcnJs.jpg" result="texture-img"/>
<feComposite in2="SourceGraphic" operator="in" in="texture-img" result="composite"/>
<feBlend in="SourceGraphic" in2="composite" mode="multiply"/>
</filter>
</defs>
<g>
<g filter="url(#texture)">
<image x="0" y="0" href="https://i.imgur.com/oVEdsQt.png" opacity="1" width="500" height="500" />
</g>
</g>
</svg>
To tile the texture, I used feTile like this
<svg preserveAspectRatio="none" width="500" height="500" viewBox="0 0 500 500">
<defs>
<filter id="texture" x="0" y="0" width="100%" height="100%">
<feImage href="https://i.imgur.com/gWH7NLm.jpg" result="texture-img" width="256" height="256"/>
<feTile in="texture-img" x="0" y="0" width="100%" height="100%" result="tile" ></feTile>
<feComposite in2="SourceGraphic" operator="in" in="tile" result="composite"/>
<feBlend in="SourceGraphic" in2="composite" mode="multiply"/>
</filter>
</defs>
<g>
<g filter="url(#texture)">
<image x="0" y="0" href="https://i.imgur.com/oVEdsQt.png" opacity="1" width="500" height="500" />
</g>
</g>
</svg>
I got the idea by checking how inkscape applies material textures

Using filters inside a external symbol

I'm trying to use a external symbol with a filter. Unfortunately it looks like the browsers don't support this feature.
Am I declaring it wrong or hasn't it been implemented?
Example page: http://www.lisa.ink/svg/
Chrome only shows the last svg
Firefox shows the first and second svg as expected
Safari only shows the last svg as expected
1. Using external symbol with only a fragment identifier
html:
<svg>
<use xlink:href="/svg/rect.svg#rect" />
</svg>
external svg:
<svg>
<defs>
<filter id="hueRotate">
<feColorMatrix in="SourceGraphic" type="hueRotate" values="90" result="A"/>
</filter>
<symbol id="rect" viewBox="0 0 640 550">
<rect x="0" y="0" width="200" height="200" fill="red" filter="url(#hueRotate)" />
</symbol>
</defs>
</svg>
2. Using a external symbol with a full IRI
html:
<svg xmlns="http://www.w3.org/2000/svg">
<use xlink:href="/svg/rect.svg#rectWithFullUrl" />
</svg>
external svg:
<svg>
<defs>
<filter id="hueRotate">
<feColorMatrix in="SourceGraphic" type="hueRotate" values="90" result="A"/>
</filter>
<symbol id="rectWithFullUrl" viewBox="0 0 640 550">
<rect x="0" y="0" width="200" height="200" fill="red" filter="url(/svg/rect.svg#hueRotate)" />
</symbol>
</defs>
</svg>
3. Using a external symbol with local
html:
<svg xmlns="http://www.w3.org/2000/svg">
<use xlink:href="/svg/rect.svg#rectWithMissingFilter" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="missingHueRotate">
<feColorMatrix in="SourceGraphic" type="hueRotate" values="90" result="A"/>
</filter>
</defs>
</svg>
external svg:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="rectWithMissingFilter" viewBox="0 0 640 550">
<rect x="0" y="0" width="200" height="200" fill="red" filter="url(#missingHueRotate)" />
</symbol>
</def>
</svg>

Resources