Using filters inside a external symbol - svg

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>

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>

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

Edge not rendering SVG Symbol

I have two pairs of SVG patterns and symbols. The symbol holds and the SVG and the pattern shapes it. I use each pattern as a fill for a Circle.
This approach works fine in chrome but in edge only some svgs render in the circle. Below is an example, on chrome you should see both a shoe and a diamond. On Edge only the diamond renders even thou the approach is the same as the shoe.
CodePen Example
<svg width="660" height="600">
<defs>
<symbol xmlns="http://www.w3.org/2000/svg" id="symbol-shoe" viewBox="0 0 45 45">
</svg>
....SVG code
</svg>
<symbol xmlns="http://www.w3.org/2000/svg" id="symbol-diamond" viewBox="0 0 45 45">
<svg>
....SVG code
</svg>
</symbol>
<pattern id="pattern-diamond" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
<use xmlns="http://www.w3.org/2000/svg" x="6.59" y="6.59" width="31.819" height="31.819" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#symbol-diamond" />
<pattern id="pattern-shoe" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
<use xmlns="http://www.w3.org/2000/svg" x="6.59" y="6.59" width="31.819" height="31.819" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#symbol-shoe" />
</pattern>
</defs>
<circle fill="url(#pattern-shoe)" cx="150" cy="150" r="60" />
<circle fill="url(#pattern-diamond)" cx="150" cy="400" r="60" />

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>

How can I get an svg symbol to reference another symbol in an external file?

I'm trying to reference a symbol inside a symbol in an external file, but can't get it to work in Chrome or Firefox.
I can reference a symbol in another symbol if they are defined at the top of the html file no problem with this:
<!-- in the html file -->
<svg width="0" height="0">
<symbol id="local-circle" viewBox="0 0 100 100" overflow="visible">
<circle
cx="50"
cy="50"
r="50"
fill="red"
/>
</symbol>
<symbol id="local-sym" viewBox="0 0 100 100" overflow="visible">
<rect
x="0"
y="0"
width="100"
height="100"
fill="blue"
/>
<use
xlink:href="#local-circle"
x="0"
y="0"
width="100"
height="100"
/>
</symbol>
</svg>
But when I try to put this code in an external file, the symbol inside a symbol doesn't show up.
<!-- in an external file called test.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
<!-- This shows up fine in the html file -->
<symbol id="ext-circle" viewBox="0 0 100 100" overflow="visible">
<circle
cx="50"
cy="50"
r="50"
fill="red"
/>
</symbol>
<!-- But here, the rect shows up, but not the referenced circle -->
<symbol id="ext-sym" viewBox="0 0 100 100" overflow="visible">
<rect
x="0"
y="0"
width="100"
height="100"
fill="blue"
/>
<use
xlink:href="#ext-circle"
x="0"
y="0"
width="100"
height="100"
/>
</symbol>
</svg>
I even tried a combination where the in-file symbol references the external symbol, but with no luck:
<!-- in the html file -->
<svg width="0" height="0">
<symbol id="combo-sym" viewBox="0 0 100 100" overflow="visible">
<rect
x="0"
y="0"
width="100"
height="100"
fill="blue"
/>
<use
xlink:href="test.svg#ext-circle"
x="0"
y="0"
width="100"
height="100"
/>
</symbol>
</svg>
Any idea how I can make this work? I will have many symbols and I don't want to have to define them all in the html file.
The external svg is invalid as it's missing an xlink namespace definition i.e. xmlns:xlink="http://www.w3.org/1999/xlink". Once I fixed that the circle shows up fine in Firefox.
<svg>
<use
xlink:href="test.svg#ext-sym"
x="0"
y="0"
width="100"
height="100"
/>
</svg>

Resources