Skip to content Skip to sidebar Skip to footer

Canvas.todataurl() Not Showing Background Image Of Canvas

I have added background image to canvas using css. But when converting it into png using canvas.toDataURL() , its not showing background image. It seems like its not parsing css b

Solution 1:

As said in comments, background-image is not part of the canvas context and thus, can't be exported by any canvas' export methods.

If you want to get this image drawn on the canvas, simply draw it before you draw the other image.* The main difficulty being to reproduce the different option CSS background has. But in your case, it's quite simple.

var svgString = newXMLSerializer().serializeToString(document.querySelector('svg'));

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

varDOMURL = self.URL || self.webkitURL || self;

var svg = newBlob([svgString], {
  type: "image/svg+xml"
});
var url = DOMURL.createObjectURL(svg);
var png = '';

var toLoad = 2;
var loaded = 0;
var background = newImage();
var svgImg = newImage();

// attach the event to both images
background.onload = svgImg.onload = function(){
 // only when both has loadedif(++loaded === toLoad){
  
  // set the canvas size to the svg image's one
  canvas.width = svgImg.width;
  canvas.height = svgImg.height;
  
  // draw the background image first
  ctx.drawImage(background, (canvas.width/2)-(background.width/2), (canvas.height/2)-(background.height/2));
	// then the svg image
  ctx.drawImage(svgImg, 0, 0);
  png = canvas.toDataURL("image/png");
  document.querySelector('#chart').innerHTML = '<img src="' + png + '"/>';
  // you want to revoke the svgImg ObjectURL, not the canvas dataURIDOMURL.revokeObjectURL(svgImg.src);
 
 }
}
svgImg.src = url;
// set it only if you're doing a cross origin request// Object URL are not
background.crossOrigin = 'anonymous';
background.src = 'https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png'
svg{border: 1px solid red;}
canvas{border: 1px solid blue;}
img{border: 1px solid green;}
<svgwidth="120"height="120"viewBox="0 0 120 120"xmlns="http://www.w3.org/2000/svg"><rectx="10"y="10"width="55"height="55"fill-opacity=".5"/></svg><canvasid="canvas"></canvas><pid="chart"></p>

*As said by markE, if you can't draw the background before, you can also set the globalCompositeOperation of your context to destination-over in order to draw behind the actual content.


Now, this wasn't clearly part of your question, but if you tried to set the background-image to your svg node, you should have been able to draw it on your canvas image, as part of the svg.

But since HTMLImage (<img>) element can't load any external resources form its loaded media, you would have to first convert the image to a dataURI version, and append the styles either as the svg's style attribute, either in a <style> element appended inside the svg element.

Here is a ugly example that will convert an svg element with a CSS defined background-image, and draw it on the canvas. Don't use it, this just here for the demo but is likely to break. Also, this has only been quickly tested against FF, Chrome and Safari.

functionconvertSVGWithBG(svg, callback) {

  // this function is not be bullet proof, better if you know the urls in advance// in case of multi-imagesvar imgsToLoad = getComputedStyle(svg).backgroundImage.split(',');

  appendDocumentStylesTo(svg);

  var toLoad = imgsToLoad.length,
    loaded = 0,
    // we need to keep it sorted
    rules = [],
    canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d');

  imgsToLoad.forEach(function(s, i) {

    var bgURL = parseURL(s),
      bgImg = newImage();
    bgImg.crossOrigin = 'anonymous';

    var errored = false;

    bgImg.onload = function() {
      canvas.width = this.width;
      canvas.height = this.height;
      ctx.drawImage(this, 0, 0);
      rules[i] = canvas.toDataURL();
      if (++loaded === toLoad) {
        onend();
      }
      bgImg.onerror = function() {

        if (!errored) {
          errored = true;
          this.crossOrigin = null;
          this.removeAttribute('crossorigin');
          this.src = this.src;
        } else {
          console.warn('failed to load img at src ', this.src);
          if (--toLoad === loaded) {
            onend();
          }
        }
      };
    };

    bgImg.src = bgURL;

    functiononend() {
      var toLoad = rules.filter(function(r) {
          return r;
        }).length,
        loaded = 0;
      // wait for the dataURI version has loaded too
      rules.forEach(function(url) {
        var img = newImage();
        img.onload = function() {
          if (++loaded === toLoad) {

            callback(svg);

          }
        };
        img.src = url
      });
      // it has to be inline style, or appended in a <style> element directly in our svg elementvar fullRule = 'url(' + rules.join('), url(') + ')';
      svg.style.backgroundImage = fullRule;
    }

  });

  functionparseURL(str) {
    // this is ugly and there should be a better way to do so (maybe regex)var url = str.split('"')[1];
    if (!url) {
      url = str.split("'")[1];
    }
    if (!url) {
      url = str.split('(')[1].split(')')[0];
    }
    return url;
  }
}

functionsvgToCanvas(svg) {

  var svgString = newXMLSerializer().serializeToString(svg);
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");

  varDOMURL = self.URL || self.webkitURL || self;

  var svg = newBlob([svgString], {
    type: "image/svg+xml"
  });
  var url = DOMURL.createObjectURL(svg);

  var svgImg = newImage();
  svgImg.onload = function() {
    canvas.width = svgImg.width;
    canvas.height = svgImg.height;
    ctx.drawImage(svgImg, 0, 0);
    png = canvas.toDataURL("image/png");
    document.querySelector('#chart').innerHTML = '<img src="' + png + '"/>';
    DOMURL.revokeObjectURL(svgImg.src);
  }
  svgImg.src = url;

}

var svg = document.querySelector('svg');
convertSVGWithBG(svg, svgToCanvas);

// this is completely unstable and should never be used...functionappendDocumentStylesTo(element) {

  var docStyleSheets = document.styleSheets;
  var i = 0,
    j, rules, r, key;
  for (i; i < docStyleSheets.length; i++) {
    rules = docStyleSheets[i].cssRules;
    for (j = 0; j < rules.length; j++) {
      r = rules[j];
      if (element.matches(r.selectorText)) {

        if (r.style) {
          for (k = 0; k < r.style.length; k++) {
            key = r.style[k];
            // ugly hack for Safariif (key.indexOf('repeat') > -1) {
              key = 'background-repeat';
            }
            element.style[key] = r.style[key];
          }
        }
      }
    }
  }

}
canvas {
  border: 1px solid blue;
}
img {
  border: 1px solid green;
}
svg {
  background-image: url(https://dl.dropboxusercontent.com/s/rumlhyme6s5f8pt/ABC.png), url(https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png);
  background-position: 50%;
  background-repeat: no-repeat;
}
<svgwidth="120"height="120"viewBox="0 0 120 120"xmlns="http://www.w3.org/2000/svg"><rectx="10"y="10"width="55"height="55"fill-opacity=".5" /></svg><canvasid="canvas"></canvas><pid="chart"></p>

Solution 2:

This solution is working 

var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));

        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        var DOMURL = self.URL || self.webkitURL || self;
        var img = new Image();
        //var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});var svg = new Blob([svgString], {type: "image/svg+xml"});
        var url = DOMURL.createObjectURL(svg);

        var png = '';
        var emailConfirmationMessage = '';
        var img1 = new Image();

        img.onload = function() {
            ctx.drawImage(img1, 136, 136);
            ctx.drawImage(img, 0, 0);

            sendEmail(canvas,DOMURL);

        };

         img1.onload = function(){
           img.src = url;
         };
        img1.src = 'chart1.png';

Post a Comment for "Canvas.todataurl() Not Showing Background Image Of Canvas"