CairoSVG icon indicating copy to clipboard operation
CairoSVG copied to clipboard

Getting AttributeError: 'Node' object has no attribute 'xml_tree' when parsing svg

Open jacobtomlinson opened this issue 7 years ago • 3 comments

When I try to run svg2png on this SVG from the yr.no weather symbols I get the following error.

SVG

<svg x="0" y="0" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">;
  <symbol id="raindrop">
    <path fill="#0062bf" d="M2.5,13A2.5,2.5,0,0,1,.21,9.51l3.55-8a2.5,2.5,0,0,1,4.57,2l-3.55,8A2.5,2.5,0,0,1,2.5,13Z"></path>
  </symbol>
  <symbol id="cloud">
    <path d="M55.7,5A23.94,23.94,0,0,0,34.37,18.05a9.9,9.9,0,0,0-12.78,5.56,15,15,0,0,0-1.71-.1A14.81,14.81,0,0,0,9.2,28,14.63,14.63,0,0,0,5,38.17v.21A14.83,14.83,0,0,0,19.88,53.06H75.59a14.3,14.3,0,0,0,3.67-28.14A23.93,23.93,0,0,0,55.7,5Z"></path>
    <image x="5" y="14" width="85" height="43" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFYAAAAkCAMAAAAkYj0PAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAVUExURSgoKExpcaCgoFBQUG5ublBQUISEhI1fsT0AAAAHdFJOUxsACBsPFRpGXuFgAAABWElEQVRIx7XV25bDIAgF0BMu/v8nF/E+iWlqHNKVN3cpIMXxL4GFM3SQfTazkUyxk63oLYwlVSy2silXkS/wUrZS2a3ZCn1zsdSw7UUYijuHsTa1IvfwWrbSXLkc4N9r27JViwmM1UtWXA3hohQ41m6vl8FQZi7wu2z7KXPW4uRiZS+2AmdXN7DdQEQWQHYHlt6z0dXBBa2xeeVktiZc1jDoF5eGkI4d4MjKc7cNbZ3bqjocLLx5oPDYTaIftcfvAvcs2GFxVsJTOP1wO1jGdUSLaz/DWA1Tl45+Tkqul2ArcPzayGq8JafOUffP3TUp6JQs+Rptc6vtmtBkUw+dv0NzWG0PYf8O7Ym09+ITXyXOPZqEX95aFe3PKxRsL2XV3HR+ZALirPSF0ceHp6F51WBv1A22VaW2GHWzWvat8LOAPf4CrjrA+neNK7+PQBf/DmmLrId09/QDWyESBsibwBUAAAAASUVORK5CYII="></image>
  </symbol>
  <symbol id="s09">
    <use xlink:href="#cloud" fill="#b2b2b2" x="0" y="0" width="100" height="100" transform="translate(3,18) scale(1,1)"></use>
    <use xlink:href="#raindrop"  x="0" y="0" width="100" height="100" transform="translate(32,78) scale(1,1)"></use>
    <use xlink:href="#raindrop"  x="0" y="0" width="100" height="100" transform="translate(45,87) scale(1,1)"></use>
    <use xlink:href="#raindrop"  x="0" y="0" width="100" height="100" transform="translate(60,78) scale(1,1)"></use>
  </symbol>
  <symbol id="sun">
    <path class="sun-glow" fill="url(#sun-glow-grad)" d="M66.64,47.86,82,41,66.64,34.12l9.84-13.66L59.76,22.22,61.46,5.47l-13.6,9.89L41,0,34.12,15.36,20.46,5.52l1.76,16.72L5.47,20.54l9.89,13.6L0,41l15.36,6.83L5.52,61.54l16.72-1.76L20.54,76.53l13.6-9.89L41,82l6.83-15.36,13.66,9.84L59.78,59.76l16.75,1.69Z"></path>
    <path class="sun-outer" fill="#ffd348" d="M19.28,53.5a25,25,0,1,0,9.15-34.16A25,25,0,0,0,19.28,53.5Z"></path>
    <path class="sun-inner" fill="url(#sun-inner-grad)" d="M22.74,51.5a21,21,0,1,0,7.69-28.69A21,21,0,0,0,22.74,51.5Z"></path>
  </symbol>

  <defs>
    <mask id="cloud_3_18_1_1_5">
    <rect x="0" y="0" width="100" height="100" fill="white"></rect>
    <use xlink:href="#cloud" fill="black" stroke="black" stroke-linejoin="round" stroke-width="10" x="0" y="0" width="100" height="100" transform="translate(3,18) scale(1,1)"></use>
  </mask>
    <radialGradient id="sun-glow-grad" cx="41" cy="41" r="41" gradientUnits="userSpaceOnUse">
      <stop offset="54%" stop-color="#d6b849"/>
      <stop offset="67%" stop-color="#ffce47"/>
      <stop offset="100%" stop-color="#ffdb73"/>
    </radialGradient>
    <linearGradient id="sun-inner-grad" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" stop-color="#ffaf22" />
      <stop offset="100%" stop-color="#f09900" />
    </linearGradient>
  </defs>
  <symbol id="s05d">
    <g mask="url(#cloud_3_18_1_1_5)">
      <use xlink:href="#sun"  x="0" y="0" width="100" height="100" transform="translate(0,2) scale(0.7,0.7)"></use>
    </g>
    <use xlink:href="#s09" x="0" y="0" width="100" height="100"></use>
  </symbol>
  <use xlink:href="#s05d" x="0" y="0" width="100" height="100"></use>
</svg>

Error


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-17-75690ad38733> in <module>()
      1 from IPython.display import Image
----> 2 Image(glyph.to_png(scale=5), retina=True)

~/metglyphs/__init__.py in to_png(self, scale)
     68         """Convert to a png."""
     69         return cairosvg.svg2png(bytestring=self.svg, 
---> 70                                 scale=scale)
     71 
     72     def to_np_array(self, scale=1):

/opt/conda/lib/python3.6/site-packages/cairosvg/__init__.py in <lambda>(*args, **kwargs)
     43         # Two lambdas needed for the closure
     44         lambda surface_type: lambda *args, **kwargs:
---> 45             surface_type.convert(*args, **kwargs))(_surface_type)
     46     _name = 'svg2{}'.format(_output_format.lower())
     47     _function.__name__ = _name

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in convert(cls, bytestring, **kwargs)
    136         output = write_to or io.BytesIO()
    137         instance = cls(
--> 138             tree, output, dpi, None, parent_width, parent_height, scale)
    139         instance.finish()
    140         if write_to is None:

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in __init__(self, tree, output, dpi, parent_surface, parent_width, parent_height, scale)
    193             width, height, viewbox, scale, preserved_ratio(tree))
    194         self.context.move_to(0, 0)
--> 195         self.draw(tree)
    196 
    197     @property

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in draw(self, node)
    411         if display and node.tag not in INVISIBLE_TAGS:
    412             for child in node.children:
--> 413                 self.draw(child)
    414 
    415         # Apply filter, mask and opacity

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in draw(self, node)
    351         if node.tag in TAGS:
    352             try:
--> 353                 TAGS[node.tag](self, node)
    354             except PointError:
    355                 # Error in point parsing, do nothing

/opt/conda/lib/python3.6/site-packages/cairosvg/defs.py in use(surface, node)
    376             tree['width'], tree['height'] = node['width'], node['height']
    377 
--> 378     surface.draw(tree)
    379     node.get('fill', None)
    380     node.get('stroke', None)

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in draw(self, node)
    411         if display and node.tag not in INVISIBLE_TAGS:
    412             for child in node.children:
--> 413                 self.draw(child)
    414 
    415         # Apply filter, mask and opacity

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in draw(self, node)
    419                 apply_filter_before_painting(self, node, filter_)
    420             if mask in self.masks:
--> 421                 paint_mask(self, node, mask, opacity)
    422             else:
    423                 self.context.paint_with_alpha(opacity)

/opt/conda/lib/python3.6/site-packages/cairosvg/defs.py in paint_mask(surface, node, name, opacity)
    162 
    163     from .surface import SVGSurface  # circular import
--> 164     mask_surface = SVGSurface(mask_node, None, surface.dpi, surface)
    165     surface.context.save()
    166     surface.context.translate(x, y)

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in __init__(self, tree, output, dpi, parent_surface, parent_width, parent_height, scale)
    193             width, height, viewbox, scale, preserved_ratio(tree))
    194         self.context.move_to(0, 0)
--> 195         self.draw(tree)
    196 
    197     @property

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in draw(self, node)
    411         if display and node.tag not in INVISIBLE_TAGS:
    412             for child in node.children:
--> 413                 self.draw(child)
    414 
    415         # Apply filter, mask and opacity

/opt/conda/lib/python3.6/site-packages/cairosvg/surface.py in draw(self, node)
    351         if node.tag in TAGS:
    352             try:
--> 353                 TAGS[node.tag](self, node)
    354             except PointError:
    355                 # Error in point parsing, do nothing

/opt/conda/lib/python3.6/site-packages/cairosvg/defs.py in use(surface, node)
    363     tree = Tree(
    364         url=href, url_fetcher=node.url_fetcher, parent=node,
--> 365         tree_cache=surface.tree_cache, unsafe=node.unsafe)
    366 
    367     if not match_features(tree.xml_tree):

/opt/conda/lib/python3.6/site-packages/cairosvg/parser.py in __init__(self, **kwargs)
    384             while root_parent.parent:
    385                 root_parent = root_parent.parent
--> 386             tree = root_parent.xml_tree
    387         else:
    388             if not bytestring:

AttributeError: 'Node' object has no attribute 'xml_tree'

jacobtomlinson avatar Feb 18 '18 13:02 jacobtomlinson

Doing a little more digging it looks like the issue happens when converting an image which contains a <use> tag within a <mask> tag.

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/mask

jacobtomlinson avatar Feb 18 '18 14:02 jacobtomlinson

Doing a little more digging it looks like the issue happens when converting an image which contains a tag within a tag.

That's a bad bug, related to #161. 4903608 gives a better crash error, but doesn't fix the issue.

liZe avatar Feb 20 '18 21:02 liZe

As a work around for now I found that running my svg's through a conversion service resulted in a non buggy image. Would be nice for this to be fixed properly though.

jacobtomlinson avatar Feb 21 '18 08:02 jacobtomlinson