fxsvgimage
fxsvgimage copied to clipboard
Decimal font sizes don't work on the 0.0-1.0 range
I have an SVGs of maps where the units are in degrees (and hence very small). This seems to make the library misbehave.
Here is a minimal example of the axis that I try to draw
<?xml version="1.0"?>
<svg height="1000.0" version="1.1" viewBox="0 0 5.0 5.0" width="1000" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<g>
<g fill="none" stroke="none" />
<g stroke-width="0.005" stroke="black">
<line x1="0.50" x2="0.50" y1="5.00" y2="4.90" />
<line x1="1.50" x2="1.50" y1="5.00" y2="4.90" />
<line x1="2.50" x2="2.50" y1="5.00" y2="4.90" />
<line x1="3.50" x2="3.50" y1="5.00" y2="4.90" />
<line x1="4.50" x2="4.50" y1="5.00" y2="4.90" />
<g fill="black" font-family="Arial, sans-serif" font-size="0.05" stroke="none" text-anchor="start" transform="translate(0.0125 -0.025)">
<text x="0.50" y="5.00">97°</text>
<text x="1.50" y="5.00">98°</text>
<text x="2.50" y="5.00">99°</text>
<text x="3.50" y="5.00">100°</text>
<text x="4.50" y="5.00">101°</text>
</g>
<line x1="0.00" x2="5.00" y1="5.00" y2="5.00" />
</g>
<g stroke-width="0.005" stroke="black">
<line x1="0.00" x2="0.10" y1="5.00" y2="5.00" />
<line x1="0.00" x2="0.10" y1="4.00" y2="4.00" />
<line x1="0.00" x2="0.10" y1="3.00" y2="3.00" />
<line x1="0.00" x2="0.10" y1="2.00" y2="2.00" />
<line x1="0.00" x2="0.10" y1="1.00" y2="1.00" />
<line x1="0.00" x2="0.10" y1="0.00" y2="0.00" />
<g fill="black" font-family="Arial, sans-serif" font-size="0.05" stroke="none" text-anchor="start" transform="translate(0.025 0.00625)">
<text x="-0.00" y="5.05">6°</text>
<text x="-0.00" y="4.05">7°</text>
<text x="-0.00" y="3.05">8°</text>
<text x="-0.00" y="2.05">9°</text>
<text x="-0.00" y="1.05">10°</text>
<text x="-0.00" y="0.05">11°</text>
</g>
<line x1="0.00" x2="0.00" y1="5.00" y2="0.00" />
</g>
</g>
</svg>
I can pare it down further:
<?xml version="1.0"?>
<svg height="1000.0" version="1.1" viewBox="0 0 5.0 5.0" width="1000" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<g>
<g fill="none" stroke="none" />
<g stroke-width="0.005" stroke="black">
<g fill="black" font-family="Arial, sans-serif" font-size="0.05" stroke="none" text-anchor="start" transform="translate(0.0125 -0.025)">
<text x="4.50" y="5.00">101°</text>
</g>
<line x1="0.00" x2="5.00" y1="5.00" y2="5.00" />
</g>
<g stroke-width="0.005" stroke="black">
<g fill="black" font-family="Arial, sans-serif" font-size="0.05" stroke="none" text-anchor="start" transform="translate(0.025 0.00625)">
<text x="-0.00" y="0.05">11°</text>
</g>
<line x1="0.00" x2="0.00" y1="5.00" y2="0.00" />
</g>
</g>
</svg>
The parameter font-size
seems to work up to the value 1.0
and then subsequently the letters stop shrinking and start to move together and overlap
Thanks for the library! It seems to work instantaneously even with large SVGs I throw at it. Just a few weird rendering edge cases to iron out - and no more Batik! :D
Here is large complex SVG that also fails:
I will look at the second problem next, but for the fonts, it's because the library does not correctly parse font sizes. It is expected that:
- For SVG, if a
is provided without a unit identifier (e.g., an unqualified number such as 128), the SVG user agent processes the as a height value in the current user coordinate system. - If a
is provided with one of the unit identifiers (e.g., 12pt or 10%), then the SVG user agent converts the into a corresponding value in the current user coordinate system by applying the rules described in Units.
I don't really take into account the first case correctly by considering it is a height in the current viewBox. I will fix the library to do that.
I partly fixed the first problem in my local repo, but fixing completely this problem will involve an extra step because JavaFX does not layout the characters of a String correctly if the font is very small. I will need to write each character one by one if the font size is below a certain value.
Sorry, I embarrassingly somehow missed the notification for your first response. So at the end of the day, from what I understood - the font size, and the text overlap are two separate issues?
It's a good point about the units. It was definitely an oversight on my part.. I'd just kept everything unitless and tweaked it till it looked good in Firefox - so it's possible I did something not very kosher.
I just did a quick test of qualifying the units. I tried to manually change the two instances of font-size="0.05"
to be font-size="0.05px"
and font-size="0.05pt"
- but I don't see any change in the render on my end. It's possible I misunderstood and that this too needs your local changes as well.
I'll try to play around with it a bit more tomorrow. I wonder if I can work around it in my svg generation pipeline with a scale transform instead of setting the font size to this tiny value. Especially if this is a weird corner case you're not particularly interested in fixing :))
Hello again, I will look at your updated example (font-size="0.05px"
and font-size="0.05pt"
) with my changes to see if they "fix" the problem. However I think that the change I envisioned with very small fonts. I think that it's not too hard to fix on my side, I will look at that ASAP.
Hopefully I'm not abusing the SVG spec here :)
I'd just note that while the SVG has units in degrees, and hence some thing like the font size end up with very small numerical values, the final render is always upscaled. So I'm not trying to render a very small image with tiny small text
The top level <svg>
tag is something like
<svg height="1000.0"
version="1.1"
viewBox="0 0 5.0 5.0"
width="1000"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg">
the viewBox
part is in effect specifying the dimension of the view area in degrees
While I could see maybe JFX hitting some edge case when rendering microscopic text - but that shouldn't be happening here. It might be architecturally challenging/irritating b/c you need to propagate all the scaling correctly and render at the very end
I did manage to bypass the issue by scaling the text instead of using a small font size.
If before I had
<g fill="black"
font-family="Arial, sans-serif"
font-size="0.05"
stroke="none"
text-anchor="start"
transform="translate(0.0125 -0.025)">
<text x="4.50"
y="5.00">
101°
</text>
</g>
I could rewrite this as
<g fill="black"
font-family="Arial, sans-serif"
font-size="5px"
stroke="none"
text-anchor="start"
transform="translate(0.0125 -0.025)">
<text x="450.0"
y="500.0"
transform="scale(0.01)">101°</text>
</g>
Now font-size
is a more reasonable 5pt
and fxsvgimage
renders everything correctly.
The downside is that this scaling is applied to the coordinates as well. So I then needed to descale the x/y. The coordinates went from being 4.5
and 5.0
degrees to being 450
and 500
.. milidegrees? haha
So the result is a little goofy but it works :))
I don't the fxsvgimage
internals, but my guess is that this font-size
problem is fixeable - just about reordering the scaling/rendering internally somewhere.
Maybe there is some other way to work around this problem though. Not sure :)
Curiously I've also rerun this using the FranzXaver
svg->jfx library and seems to also blows up the text in an identical way. I'm not super familiar with its internals - I thought it uses Batik, but the output doesn't look like a raster image