meerk40t / svgelements

SVG Parsing for Elements, Paths, and other SVG Objects.
MIT License
127 stars 28 forks source link

Parsing Inkscape text elements results in missing element IDs #157

Closed baender closed 2 years ago

baender commented 2 years ago

When trying to access text elements created in Inkscape, the parser does not get the element ids correctly. This might be due to id="text3785"><tspan and a simple regular expression could solve the issue.

import svgelements

# svgFileName = "path/to/svg"

layout = svgelements.SVG.parse(
    source = svgFileName, 
    reify = True,
    ppi = svgelements.svgelements.DEFAULT_PPI,
    width = 1,
    height = 1,
    color = "black",
    transform = None,
    context = None
)

[element.id for element in layout.elements()]
# ['svg3040', 'namedview3042', 'layer1', None, None, None, None, None, None]
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   width="210mm"
   height="297mm"
   viewBox="0 0 210 297"
   version="1.1"
   id="svg3040"
   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
   sodipodi:docname="test12.svg"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <sodipodi:namedview
     id="namedview3042"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageshadow="2"
     inkscape:pageopacity="0.0"
     inkscape:pagecheckerboard="0"
     inkscape:document-units="mm"
     showgrid="false"
     inkscape:zoom="0.72337262"
     inkscape:cx="396.75265"
     inkscape:cy="561.95105"
     inkscape:window-width="1920"
     inkscape:window-height="1001"
     inkscape:window-x="-9"
     inkscape:window-y="-9"
     inkscape:window-maximized="1"
     inkscape:current-layer="layer1" />
  <defs
     id="defs3037" />
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1">
    <text
       xml:space="preserve"
       style="font-size:18px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583"
       x="30.724138"
       y="44.988914"
       id="text3785"><tspan
         sodipodi:role="line"
         id="tspan3783"
         style="stroke-width:0.264583"
         x="30.724138"
         y="44.988914">Test</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:18px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583"
       x="67.300491"
       y="110.46059"
       id="text4119"><tspan
         sodipodi:role="line"
         id="tspan4117"
         style="stroke-width:0.264583"
         x="67.300491"
         y="110.46059">TestTest</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:18px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583"
       x="67.300491"
       y="172.6404"
       id="text4519"><tspan
         sodipodi:role="line"
         id="tspan4517"
         style="stroke-width:0.264583"
         x="67.300491"
         y="172.6404">123</tspan></text>
  </g>
</svg>
tatarize commented 2 years ago

Hm. Tested that and you're right. It's likely unrelated to that bit since it's not regexed it's parsed with the xml and should be done correctly. It's something in svgelements failing to save the id. Likely it relates to it being a text object in general since they tend to nest inside each other and only become relevant after they close (since the internal text matters to the tags) and svgelements has a text object alone rather than text and tspan. Or it could just be failure to parse the id. I'll fix it pretty quick.

    def test_issue_157(self):
        q = io.StringIO(u'''<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg>
  <g id="layer1">
    <text
       style="font-size:18px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583"
       id="textobject"><tspan
         id="tspanobject"
         x="0"
         y="0">Test</tspan></text>
  </g>
</svg>
        ''')
        m = SVG.parse(q)
        q = list(m.elements())
        self.assertIsNotNone(q[1].id) # Group
        self.assertIsNotNone(q[2].id) # Text
        self.assertIsNotNone(q[3].id) # TSpan

This test does fail and that is clearly in error.