Typesetting multiline text in SVG

Having worked on rendering text on my AxiDraw, the next question is how to typeset text. The challenge is SVG 1.1 text elements are explicitly single line, no automatic wrapping. There’s no text flow in an SVG renderer, you have to do it yourself. (SVG 2.0 promises to add this, and I guess there was an ill fated effort in SVG 1.2).

There is a nice way to express multiline text in SVG using the <tspan> element.

    <text class="verse">                                   
        <tspan dy="1.2em" x="10"
               >How doth the little crocodile</tspan>      
        <tspan dy="1.2em" x="10" dx="1em"
               >Improve his shining tail,</tspan>          
        <tspan dy="1.2em" x="10"
               >And pour the waters of the Nile</tspan>
        <tspan dy="1.2em" x="10" dx="1em"
               >On every golden scale!</tspan>

Note the use of dy to do the line spacing; that’s nearly automatic. (the dx parts are for some fancy indentation. Not sure why x is being set explicitly every time.) All you have to do is decide where to break the lines! Ha.

There’s also some support for automated kerning with the textLength attribute.

I can’t find a Python library that will break lines for you or do more fancy automated typesetting. It is possible in Javascript, or at least you can write code to do it, using the getBBox() function to inspect the pixel size of some text and use that to break lines.

One approach in Python would be to calculate metrics for a font and then use that to estimate the width of a word. That won’t work if the kerning isn’t predictable. Also it’s a lot of work to do right for arbitrary fonts.

A second approach is to use something to render SVG in Python and use that to measure widths. Something like the pyrsvg wrapper for librsvg. That’s a lot of code to bring in though and I’m not confident it would perform very well. py3rsvg looks promising as a lighter / standalone option. See also this discussion.

A third option is to skip SVG text entirely and work directly with HersheyFonts generated paths in Python. The library has support for inspecting the width of glyphs; bounding box, etc. But this library is a separate work from the Evil Mad Scientist / AxiDraw code for Hershey text, the one that’s an Inkscape extension. They’ve done some nice work on fonts, etc so I’m not sure how much you’re giving up going with this other code instead. SVG Fonts, for one; I think the HersheyFonts library is using the actual Hershey format. That means no Unicode. I’m not sure the ESM HersheyText Inkscape code can be repurposed though, it seems to be written in a very Inkscape-specific way and relying on their renderer. I could be wrong about that though.

I think that last option may be best; it’s closer to the actual SVG I want to send to the plotter.