yWorks / svg2pdf.js

A javascript-only SVG to PDF conversion utility that runs in the browser. Brought to you by yWorks - the diagramming experts
MIT License
654 stars 101 forks source link

Exception when clipPath is not defined in the defs but in the same <g> element #55

Closed fskpf closed 5 years ago

fskpf commented 5 years ago

An exception is thrown if an element has a clip-path and the referenced clipPath is not defined in the defs, but in the same element:

              <g transform="matrix(0 -1 1 0 30 50)">
                <text font-family="Arial" font-size="12px" font-style="normal" font-weight="normal" text-anchor="middle" fill="rgb(0,0,0)" fill-opacity="1" transform="translate(25 9)" clip-path="url(#ygc341_0)">
                  <tspan x="0" dy="0.9166666666666666em">LDC</tspan>
                  <tspan x="0" dy="1.5em">(Distributor)</tspan>
                </text>
                <clipPath id="ygc341_0">
                  <rect height="50" y="-9" x="-25" width="50"/>
                </clipPath>
              </g>

Throws Uncaught TypeError: Cannot read property 'hasAttribute' of undefined. This seems to be due to the implementation only looking in the defs elements:

      var clipPathNode = getFromDefs(svgIdPrefix.get() + clipPathId[1], defs); // <<<---- defs is empty

      var clipPathMatrix = tfMatrix;
      if (clipPathNode.hasAttribute("clipPathUnits") // <<<----- exception
          && clipPathNode.getAttribute("clipPathUnits").toLowerCase() === "objectboundingbox") {
        bBox = getUntransformedBBox(node);
        clipPathMatrix = _pdf.matrixMult(new _pdf.Matrix(bBox[2], 0, 0, bBox[3], bBox[0], bBox[1]), clipPathMatrix);
      }

Maybe the clipPathNode access should be checked for null, though ideally the actual clipPath element should be found. Attached is a repo of the exception: broken-clippath_html.txt

yGuy commented 5 years ago

Note that the clippath element could be anywhere in the SVG document:

An IRI reference to another graphical object within the same SVG document fragment which will be used as the clipping path. If the IRI reference is not valid (e.g it points to an object that doesn't exist or the object is not a ‘clipPath’ element) the ‘clip-path’ property must be treated as if it hadn't been specified.