Does not support <image> tags linking to SVG images
Closed this issue · 11 comments
Consider the following image that Chrome renders correctly:
<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<image xmlns:foo="http://www.w3.org/1999/xlink" foo:href="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/android.svg" width="96" height="105" />
</svg>
There are two issues here for jsvg, one is the namespace alias (it looks explicitly for href
or xlink:href
), this to me is a minor issue.
The other is that it does not support rendering linked SVGs.
Do you think this is something that could be reasonably supported by jsvg?
The use case that I ran into was making a composite SVG out of multiple others, for example to show different layers of a building floor plan.
Are in your scenario the other svg files located locally on the file system or on a web server? The latter might complicate things?
For a first step I could support this only with the restriction that the references svg is first rendered to a BufferedImage
.
The implementation would just be to complete #1 (which I wanted to postpone until it is needed :D).
More complicated would be to render the referenced svg as a SVGDocument
. Though the current architecture should accommodate it with a few adjustments.
Supporting namespaces properly is a bigger can of worms, which I am not too sure about whether the effort is worth it considering the svg 2 spec wants to move away from them for the href
attribute.
I didn't spot that issue, nice!
They are locally on the filesystem, I used an external URL for demonstration purposes.
If the SVG spec says to treat SVG as raster images then that sounds good to me. If there turns out to be a need to handle them as SVGDocument
s, I guess the ParserProvider
could be extended to create an image parser that could somehow transform an Image
element to an SVG
one, for example.
Fair enough about the namespaces, in this case I'm able to "fix" them through the ParserProvider
.
Actually looking into it I think for now it is actually easier to paint it as a SVGDocument
if one want to respect the width
and height
attribute of the <image>
tag 😅
Thank you for looking into it!
At least for my particular use case, both approaches work. 🙂
The implementation wasn't actually that difficult. I still need to work out configuration of the used SVGLoader
. Though the basic use case should be covered with the latest snapshot version.
I tried it out, works perfectly for my use case! Very much appreciated!
Are you enabling external images as described above? Also could you please put the xml code for the svg into your comment (makes it easier to follow the discussion without having to open it in an external editor)
Are you enabling external images as described above?
not sure what you mean
Also could you please put the xml code for the svg into your comment
Yes sorry
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" class="marks"
width="274" height="260" viewBox="0 0 274 260">
<rect width="274" height="260" fill="white"/>
<g fill="none" stroke-miterlimit="10" transform="translate(51,23)">
<g class="mark-group role-frame root" role="graphics-object" aria-roledescription="group mark container">
<g transform="translate(0,0)">
<path class="background" aria-hidden="true" d="M0.5,0.5h200v200h-200Z" stroke="#ddd"/>
<g>
<g class="mark-group role-axis" aria-hidden="true">
<g transform="translate(0.5,200.5)">
<path class="background" aria-hidden="true" d="M0,0h0v0h0Z" pointer-events="none"/>
<g>
<g class="mark-rule role-axis-grid" pointer-events="none">
<line transform="translate(0,-200)" x2="0" y2="200" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(38,-200)" x2="0" y2="200" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(77,-200)" x2="0" y2="200" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(115,-200)" x2="0" y2="200" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(154,-200)" x2="0" y2="200" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(192,-200)" x2="0" y2="200" stroke="#ddd" stroke-width="1"
opacity="1"/>
</g>
</g>
<path class="foreground" aria-hidden="true" d="" pointer-events="none" display="none"/>
</g>
</g>
<g class="mark-group role-axis" aria-hidden="true">
<g transform="translate(0.5,0.5)">
<path class="background" aria-hidden="true" d="M0,0h0v0h0Z" pointer-events="none"/>
<g>
<g class="mark-rule role-axis-grid" pointer-events="none">
<line transform="translate(0,200)" x2="200" y2="0" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(0,162)" x2="200" y2="0" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(0,123)" x2="200" y2="0" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(0,85)" x2="200" y2="0" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(0,46)" x2="200" y2="0" stroke="#ddd" stroke-width="1"
opacity="1"/>
<line transform="translate(0,8)" x2="200" y2="0" stroke="#ddd" stroke-width="1"
opacity="1"/>
</g>
</g>
<path class="foreground" aria-hidden="true" d="" pointer-events="none" display="none"/>
</g>
</g>
<g class="mark-group role-axis" role="graphics-symbol" aria-roledescription="axis"
aria-label="X-axis titled 'x' for a linear scale with values from 0.0 to 2.6">
<g transform="translate(0.5,200.5)">
<path class="background" aria-hidden="true" d="M0,0h0v0h0Z" pointer-events="none"/>
<g>
<g class="mark-rule role-axis-tick" pointer-events="none">
<line transform="translate(0,0)" x2="0" y2="5" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(38,0)" x2="0" y2="5" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(77,0)" x2="0" y2="5" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(115,0)" x2="0" y2="5" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(154,0)" x2="0" y2="5" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(192,0)" x2="0" y2="5" stroke="#888" stroke-width="1"
opacity="1"/>
</g>
<g class="mark-text role-axis-label" pointer-events="none">
<text text-anchor="start" transform="translate(0,15)" font-family="sans-serif"
font-size="10px" fill="#000" opacity="1">0.0
</text>
<text text-anchor="middle" transform="translate(38.46153846153846,15)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">0.5
</text>
<text text-anchor="middle" transform="translate(76.92307692307692,15)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">1.0
</text>
<text text-anchor="middle" transform="translate(115.38461538461537,15)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">1.5
</text>
<text text-anchor="middle" transform="translate(153.84615384615384,15)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">2.0
</text>
<text text-anchor="middle" transform="translate(192.3076923076923,15)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">2.5
</text>
</g>
<g class="mark-rule role-axis-domain" pointer-events="none">
<line transform="translate(0,0)" x2="200" y2="0" stroke="#888" stroke-width="1"
opacity="1"/>
</g>
<g class="mark-text role-axis-title" pointer-events="none">
<text text-anchor="middle" transform="translate(100,30)" font-family="sans-serif"
font-size="11px" font-weight="bold" fill="#000" opacity="1">x
</text>
</g>
</g>
<path class="foreground" aria-hidden="true" d="" pointer-events="none" display="none"/>
</g>
</g>
<g class="mark-group role-axis" role="graphics-symbol" aria-roledescription="axis"
aria-label="Y-axis titled 'y' for a linear scale with values from 0.0 to 2.6">
<g transform="translate(0.5,0.5)">
<path class="background" aria-hidden="true" d="M0,0h0v0h0Z" pointer-events="none"/>
<g>
<g class="mark-rule role-axis-tick" pointer-events="none">
<line transform="translate(0,200)" x2="-5" y2="0" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(0,162)" x2="-5" y2="0" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(0,123)" x2="-5" y2="0" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(0,85)" x2="-5" y2="0" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(0,46)" x2="-5" y2="0" stroke="#888" stroke-width="1"
opacity="1"/>
<line transform="translate(0,8)" x2="-5" y2="0" stroke="#888" stroke-width="1"
opacity="1"/>
</g>
<g class="mark-text role-axis-label" pointer-events="none">
<text text-anchor="end" transform="translate(-7,203)" font-family="sans-serif"
font-size="10px" fill="#000" opacity="1">0.0
</text>
<text text-anchor="end" transform="translate(-7,164.53846153846155)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">0.5
</text>
<text text-anchor="end" transform="translate(-7,126.07692307692308)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">1.0
</text>
<text text-anchor="end" transform="translate(-7,87.61538461538463)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">1.5
</text>
<text text-anchor="end" transform="translate(-7,49.15384615384617)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">2.0
</text>
<text text-anchor="end" transform="translate(-7,10.69230769230771)"
font-family="sans-serif" font-size="10px" fill="#000" opacity="1">2.5
</text>
</g>
<g class="mark-rule role-axis-domain" pointer-events="none">
<line transform="translate(0,200)" x2="0" y2="-200" stroke="#888" stroke-width="1"
opacity="1"/>
</g>
<g class="mark-text role-axis-title" pointer-events="none">
<text text-anchor="middle"
transform="translate(-35,100) rotate(-90) translate(0,-2)"
font-family="sans-serif" font-size="11px" font-weight="bold" fill="#000"
opacity="1">y
</text>
</g>
</g>
<path class="foreground" aria-hidden="true" d="" pointer-events="none" display="none"/>
</g>
</g>
<g class="mark-image role-mark marks" role="graphics-object"
aria-roledescription="image mark container">
<image aria-label="x: 0.5; y: 0.5; img: data/ffox.png" role="graphics-symbol"
aria-roledescription="image mark" xlink:href="data/ffox.png"
transform="translate(13.46153846153846,136.53846153846155)" width="50" height="50"
preserveAspectRatio="xMidYMid"/>
<image aria-label="x: 1.5; y: 1.5; img: data/gimp.png" role="graphics-symbol"
aria-roledescription="image mark" xlink:href="data/gimp.png"
transform="translate(90.38461538461537,59.61538461538463)" width="50" height="50"
preserveAspectRatio="xMidYMid"/>
<image aria-label="x: 2.5; y: 2.5; img: data/7zip.png" role="graphics-symbol"
aria-roledescription="image mark" xlink:href="data/7zip.png"
transform="translate(167.3076923076923,-17.307692307692292)" width="50" height="50"
preserveAspectRatio="xMidYMid"/>
</g>
</g>
<path class="foreground" aria-hidden="true" d="" display="none"/>
</g>
</g>
</g>
</svg>
Please try the latest snapshot version. To enable loading of external resources you have to specify so during loading using the LoaderContext
e.g. LoaderContext.builder().externalResourcePolicy(ExternalResourcePolicy.ALLOW_ALL)
.