Canvg not supporting css

拟墨画扇 提交于 2019-12-12 18:12:26

问题


I have inline svg with is loaded dynamically from server. I want that svg to be manupulated or modifed using inline css. I have searched for converting that modified svg into png or base64 image. After long search i have decided to stick with Canvg.

Now the problem is that it renders the inline style attributes like background and border radius.

This is my svg.

<svg height="550" width="550" viewBox="0 0 512 512" id="svg">
<path d="m309 139c0-111-32-139-53-139-21 0-53 28-53 139l-173 122c-2 1-4 4-4 7l0 46c0 6 5 10 11 9l166-37c6 49 16 93 23 139l-63 49c-2 1-4 4-4 6l0 23c0 7 6 11 12 8l85-38 85 38c6 3 12-1 12-8l0-23c0-2-2-5-4-6l-63-49c7-46 17-90 23-139l166 37c6 1 11-3 11-9l0-46c0-3-2-6-4-7z m-53-88c-11 0-21 3-30 7 3-13 15-22 30-22 15 0 27 9 30 22-9-4-19-7-30-7z"></path>
</svg>

Which looks like this:

Remember the path is dynamically loaded from server. So cannot modify it.

Now i want to manupulate it something like this.

<svg style="background: grey none repeat scroll 0% 0%; fill: white; padding: 70px; border-radius: 98px;" height="550" width="550" viewBox="0 0 512 512" id="svg">
      <path d="m309 139c0-111-32-139-53-139-21 0-53 28-53 139l-173 122c-2 1-4 4-4 7l0 46c0 6 5 10 11 9l166-37c6 49 16 93 23 139l-63 49c-2 1-4 4-4 6l0 23c0 7 6 11 12 8l85-38 85 38c6 3 12-1 12-8l0-23c0-2-2-5-4-6l-63-49c7-46 17-90 23-139l166 37c6 1 11-3 11-9l0-46c0-3-2-6-4-7z m-53-88c-11 0-21 3-30 7 3-13 15-22 30-22 15 0 27 9 30 22-9-4-19-7-30-7z"></path>      </svg>

Which would look like this:

But after rendering using canvg script. It renders as raw file. It just includes the fill color. Nothing else.

Is there any other way to do that. Using canvas or svg elements.

Please Help!!! Thanks in advance


回答1:


Most svg to canvas libraries don't support external resources (xlink attributes, images, and CSS).

The only way I've found to do it is to append those external resources into the svg node, then use the canvas.toDataURL() method to draw your svg onto the canvas.

I am writing a small script that do handle this and here is a dump of the CSS parser I made which will loop through all document's stylesheets and only append the ones that do have an influence on inner elements.

var parseStyles = function() {
    var styleSheets = [],
        i;
    // get the stylesheets of the document (ownerDocument in case svg is in <iframe> or <object>)
    var docStyles = svg.ownerDocument.styleSheets;
    // transform the live StyleSheetList to an array to avoid endless loop
    for (i = 0; i < docStyles.length; i++) {
        styleSheets.push(docStyles[i]);
    }
    if (styleSheets.length) {
        // getDef() will return an svg <defs> element if already into the node, or will create it otherwise
        getDef();
        svg.matches = svg.matches || svg.webkitMatchesSelector || svg.mozMatchesSelector || svg.msMatchesSelector || svg.oMatchesSelector;
    }

    // iterate through all document's stylesheets
    for (i = 0; i < styleSheets.length; i++) {
        // create a new style element
        var style = document.createElement('style');
        // some stylesheets can't be accessed and will throw a security error
        try {
            var rules = styleSheets[i].cssRules,
                l = rules.length;
            // iterate through each cssRules of this stylesheet
            for (var j = 0; j < l; j++) {
                // get the selector of this cssRules
                var selector = rules[j].selectorText;
                // is it our svg node or one of its children ?
                if ((svg.matches && svg.matches(selector)) || svg.querySelector(selector)) {
                    // append it to our <style> node
                    style.innerHTML += rules[j].cssText + '\n';
                }
            }
            // if we got some rules
            if (style.innerHTML) {
                // append the style node to the clone's defs
                defs.appendChild(style);
            }
        } catch (e) {
            console.warn('unable to get some cssRules : ', e);
        }
    }
    // small hack to avoid border and margins being applied inside the <img>
    var s = clone.style;
    s.border = s.padding = s.margin = 0;
    s.transform = 'initial';
};

var svg = document.querySelector('svg');
var doSomethingWith = function(canvas) {
  document.body.appendChild(canvas)
};



var parseStyles = function() {
  var styleSheets = [],
    i;
  // get the stylesheets of the document (ownerDocument in case svg is in <iframe> or <object>)
  var docStyles = svg.ownerDocument.styleSheets;
  // transform the live StyleSheetList to an array to avoid endless loop
  for (i = 0; i < docStyles.length; i++) {
    styleSheets.push(docStyles[i]);
  }
  if (styleSheets.length) {
    // getDef() will return an svg <defs> element if already into the node, or will create it otherwise
    getDef();
    svg.matches = svg.matches || svg.webkitMatchesSelector || svg.mozMatchesSelector || svg.msMatchesSelector || svg.oMatchesSelector;
  }

  // iterate through all document's stylesheets
  for (i = 0; i < styleSheets.length; i++) {
    // create a new style element
    var style = document.createElement('style');
    // some stylesheets can't be accessed and will throw a security error
    try {
      var rules = styleSheets[i].cssRules,
        l = rules.length;
      // iterate through each cssRules of this stylesheet
      for (var j = 0; j < l; j++) {
        // get the selector of this cssRules
        var selector = rules[j].selectorText;
        // is it our svg node or one of its children ?
        if ((svg.matches && svg.matches(selector)) || svg.querySelector(selector)) {
          // append it to our <style> node
          style.innerHTML += rules[j].cssText + '\n';
        }
      }
      // if we got some rules
      if (style.innerHTML) {
        // append the style node to the clone's defs
        defs.appendChild(style);
      }
    } catch (e) {
      console.warn('unable to get some cssRules : ', e);
    }
  }
  // small hack to avoid border and margins being applied inside the <img>
  var s = svg.style;
  s.border = s.padding = s.margin = 0;
  s.transform = 'initial';
  exportDoc();
};

var defs;
var getDef = function() {
  // Do we have a `<defs>` element already ?
  defs = svg.querySelector('defs') || document.createElementNS('http://www.w3.org/2000/svg', 'defs');
  if (!defs.parentNode) {
    svg.insertBefore(defs, svg.firstElementChild);
  }
};

var exportDoc = function() {
  // check if our svgNode has width and height properties set to absolute values
  // otherwise, canvas won't be able to draw it
  var bbox = svg.getBoundingClientRect();

  if (svg.width.baseVal.unitType !== 1) svg.setAttribute('width', bbox.width);
  if (svg.height.baseVal.unitType !== 1) svg.setAttribute('height', bbox.height);

  // serialize our node
  var svgData = (new XMLSerializer()).serializeToString(svg);
  // remember to encode special chars
  var svgURL = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);

  var svgImg = new Image();

  svgImg.onload = function() {
    var canvas = document.createElement('canvas');
    // IE11 doesn't set a width on svg images...
    canvas.width = this.width || bbox.width;
    canvas.height = this.height || bbox.height;

    canvas.getContext('2d').drawImage(svgImg, 0, 0, canvas.width, canvas.height);
    doSomethingWith(canvas)
  };

  svgImg.src = svgURL;
};

parseStyles();
rect {
  fill: red;
  padding: 25em;
  border: 25px solid yellow;
}
canvas {
  border: 1px solid green;
}
svg{
  background-color: skyblue;
}
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
  <rect x="0" y="0" width="100" height="100" />
</svg>



回答2:


You can use Javascript and the DOM to modify any element in the current page; regardless wether it's server generated a file or anything else. http://www.i-programmer.info/programming/graphics-and-imaging/3254-svg-javascript-and-the-dom.html



来源:https://stackoverflow.com/questions/34121022/canvg-not-supporting-css

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!