Canvas.toDataURL()不显示画布的背景图像

时间:2016-09-27 15:05:09

标签: html5 d3.js svg html5-canvas fabricjs

我已使用css将背景图像添加到画布。

但是当使用canvas.toDataURL()将其转换为png时,它没有显示背景图像。

好像它没有解析css背景图片。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Untitled</title>

    <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.914/styles/kendo.common.min.css">
    <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.914/styles/kendo.default.min.css">

    <script src="http://code.jquery.com/jquery-1.12.3.min.js"></script>
    <script src="http://kendo.cdn.telerik.com/2016.3.914/js/kendo.all.min.js"></script>
  </head>
  <body>

    <div id="invoices-grid"></div>

    <script>
      $(function() {

        var d = [];

        for (var i = 1; i <= 100; i++) {
          d.push({Id: i, CustomerName: "CustomerName " + i});
        }

        $("#invoices-grid").kendoGrid({
          dataSource: {
            data: d,
            schema: {
              model: {
                id: "Id",
                fields: {
                  CustomerName: { type: "string" }
                }
              }
            },

            error: function(e) {
              display_kendoui_grid_error(e);
              // Cancel the changes
              this.cancelChanges();
            },
            pageSize: 20,
            //serverPaging: true,
            //serverFiltering: true,
            //serverSorting: true
          },


          columns: [

            {
              field: "CustomerName",
              title: "gp.Invoice.Fields.CustomerName",
              template: '#= CustomerName #'
            },
            {
              field: "Id",
              title: "Common.Edit",
              width: 100,
              template: '<a href="Edit/#=Id#">Common.Edit</a>'
            },

          ],
          pageable: {
            refresh: true,
            pageSizes: [5, 10, 20, 50]
          },
          editable: {
            confirmation: false,
            mode: "popup"
          },
          scrollable: false,

          selectable: true,
          change: function(e) {
          }


        });
      });

    </script>

  </body>
</html>

2 个答案:

答案 0 :(得分:1)

如评论中所述,background-image不是画布上下文的一部分,因此无法通过任何画布的导出方法导出。

如果你想在画布上绘制这个图像,只需在绘制另一个图像之前绘制它。*主要的难点是重现CSS背景的不同选项。但在你的情况下,它很简单。

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 svg = new Blob([svgString], {
  type: "image/svg+xml"
});
var url = DOMURL.createObjectURL(svg);
var png = '';

var toLoad = 2;
var loaded = 0;
var background = new Image();
var svgImg = new Image();

// attach the event to both images
background.onload = svgImg.onload = function(){
 // only when both has loaded
 if(++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 dataURI
  DOMURL.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;}
<svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
  <rect x="10" y="10" width="55" height="55" fill-opacity=".5"/>
</svg>

<canvas id="canvas"></canvas>

<p id="chart"></p>

*正如markE所说,如果您无法在之前绘制背景,您还可以将上下文的globalCompositeOperation设置为destination-over以便绘制<强>落后实际内容。

现在,这显然不是你问题的一部分,但是如果你试图将background-image设置为你的svg节点,那么你应该能够在你的画布上绘制它,作为svg的一部分。

但由于HTMLImage(<img>)元素无法从其加载的媒体加载任何外部资源,因此您必须先将图像转换为dataURI版本,然后将样式附加为svg的{{1 }},在svg元素内附加的style元素中。

这是一个丑陋的例子,它将使用CSS定义的背景图像转换svg元素,并在画布上绘制。
不要使用它,这只是为了演示,但可能会破坏。此外,这只是针对FF,Chrome和Safari进行了快速测试。

<style>
function convertSVGWithBG(svg, callback) {

  // this function is not be bullet proof, better if you know the urls in advance

  // in case of multi-images
  var 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 = new Image();
    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;

    function onend() {
      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 = new Image();
        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 element
      var fullRule = 'url(' + rules.join('), url(') + ')';
      svg.style.backgroundImage = fullRule;
    }

  });

  function parseURL(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;
  }
}

function svgToCanvas(svg) {

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

  var DOMURL = self.URL || self.webkitURL || self;

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

  var svgImg = new Image();
  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...
function appendDocumentStylesTo(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 Safari
            if (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;
}

答案 1 :(得分:0)

<flow name="testdbFlow">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/test" doc:name="HTTP"/>
    <set-payload value="{&quot;1234567890123456&quot;:&quot;Y&quot;,&quot;1234567890123457&quot;:&quot;Y&quot;}" mimeType="application/json" doc:name="Set Payload"/>
    <dw:transform-message doc:name="Transform Message">
        <dw:input-payload />
        <dw:set-payload><![CDATA[%dw 1.0
            %output application/json
            ---
            (payload mapObject {    
                x: {
                    key : $$,
                    value : $
                }
            }).*x]]>
        </dw:set-payload>
    </dw:transform-message>
    <json:json-to-object-transformer returnClass="java.util.List" doc:name="JSON to Object"/>
    <db:update config-ref="MySQL_Configuration" bulkMode="true" doc:name="Database">
        <db:dynamic-query><![CDATA[UPDATE cwg_ws_data SET SyncFlag = '#[payload.value]' WHERE IMEI = '#[payload.key]']]></db:dynamic-query>
    </db:update>
</flow>