deeplook / svglib

Read SVG files and convert them to other formats.
GNU Lesser General Public License v3.0
307 stars 79 forks source link

"ex" and "ch" must be assumed as em/2 #355

Closed thisismiller closed 1 year ago

thisismiller commented 1 year ago

My interest in this is specifically support for ch, as it's the only way to get SVGs to be able to get lines aligned with text well.

W3 offers guidance on what to do when you can't inspect the text to determine the x-height (ex) or the advance measure of a 0 glyph (ch).

There's precedent in both CairoSVG and ImageMagick which have already adopted em / 2.0 as their way to interpret ex, so with this change, I'm only suggesting that svglib do the same.

Neither currently support ch, but it's good to follow W3's advice.


Here's the motivating case of an SVG I made:

ophistory_all

This probably renders fine, as you're looking at it from a webbrowser, which understands how to render ch correctly.

Currently, processing this SVG into a png with svglib+reportlab gives an error like:

Traceback (most recent call last):
  File "/home/miller/ws/ophistory/./ophistory.py", line 354, in <module>
    main(sys.argv)
  File "/home/miller/ws/ophistory/./ophistory.py", line 348, in main
    drawing = svg2rlg(f)
  File "/home/miller/.local/lib/python3.10/site-packages/svglib/svglib.py", line 1404, in svg2rlg
    drawing = svgRenderer.render(svg_root)
  File "/home/miller/.local/lib/python3.10/site-packages/svglib/svglib.py", line 502, in render
    view_box = self.get_box(node, default_box=True)
  File "/home/miller/.local/lib/python3.10/site-packages/svglib/svglib.py", line 768, in get_box
    width, height = map(self.attrConverter.convertLength, (width, height))
  File "/home/miller/.local/lib/python3.10/site-packages/svglib/svglib.py", line 334, in convertLength
    length = toLength(text)  # this does the default measurements such as mm and cm
  File "/home/miller/.local/lib/python3.10/site-packages/reportlab/lib/units.py", line 30, in toLength
    raise ValueError("Can't convert '%s' to length" % s)
ValueError: Can't convert '197ch' to length

With the change I have proposed, the diagram renders to a .png via svglib like:

ophistory_all_svglib

And so even if assuming 0.5em is slightly inaccurate, is such an incredible improvement that I think it justifies using ex as an approximation for ch.