当前位置:  开发笔记 > 编程语言 > 正文

使用canvas.toDataURL时如何设置crossOrigin属性?

如何解决《使用canvas.toDataURL时如何设置crossOrigin属性?》经验,为你挑选了1个好方法。

所以我正在尝试为我正在构建的OpenLayers 3应用程序创建打印映射函数.我知道他们的例子,但每当我尝试使用它时,我都遇到了可怕的污点画布问题.我已经阅读了整个互联网并且遇到了人们首先正确设置CORS(完成和完成)但也要做:

          var img = new Image();
          img.setAttribute('crossOrigin', 'anonymous');
          img.src = url;

以上描述了在这里.

我的问题是,我以前从未真正使用过toDataURL(),而且我不确定如何确保正在创建的图像在被激活之前正确设置了crossOrigin属性:

Error: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

有什么想法吗?

我见过这个.我的问题是他们如何将其纳入一个有效的功能.就像是:

    var printMap = function(){
     var img = new Image();
     img.setAttribute('crossOrigin', 'anonymous');
     img.src = url;
     img.onload = function() {
      var canvas = document.getElementsByTagName('canvas');
      var dataURL = canvas.toDataURL("image/png");
      console.log(dataURL);
     };
   };

Kaiido.. 7

如果crossOrigin浏览器支持属性/属性(现在它在FF,Chrome,最新的Safari和Edge中),但是服务器没有使用正确的标题(Access-Control-Allow-Origin: *)回答,那么img的onerror事件就会触发.

因此,如果我们想要绘制图像,我们可以只处理此事件并删除属性.
对于不处理此属性的浏览器,测试画布是否被污染的唯一方法是调用toDataURLtry catch块.

这是一个例子:

var urls = 
    ["http://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png", 
     "http://lorempixel.com/200/200"];

	var tainted = false;

	var img = new Image();
	img.crossOrigin = 'anonymous';

	var canvas = document.createElement('canvas');
	var ctx = canvas.getContext('2d');
	document.body.appendChild(canvas);

	var load_handler = function() {
	  canvas.width = 200;
	  canvas.height = 200;

	  ctx.fillStyle = 'white';
	  ctx.font = '15px sans-serif';

	  ctx.drawImage(this, 0, 0, 200, 200*(this.height/this.width));

	  // for browsers supporting the crossOrigin attribute
	  if (tainted) {
	    ctx.strokeText('canvas tainted', 20, 100);
	    ctx.fillText('canvas tainted', 20, 100);
	  } else {
	    // for others
	    try {
	      canvas.toDataURL();
	    } catch (e) {
	      tainted = true;
	      ctx.strokeText('canvas tainted after try catch', 20, 100);
	      ctx.fillText('canvas tainted after try catch', 20, 100);
	    }
	  }
	};

	var error_handler = function() {
	  // remove this onerror listener to avoid an infinite loop
	  this.onerror = function() {
	    return false
	  };
	  // certainly that the canvas was tainted
	  tainted = true;

	  // we need to removeAttribute() since chrome doesn't like the property=undefined way...
	  this.removeAttribute('crossorigin');
	  this.src = this.src;
	};

	img.onload = load_handler;
	img.onerror = error_handler;

	img.src = urls[0];

	btn.onclick = function() {
	  // reset the flag
	  tainted = false;

	  // we need to create a new canvas, or it will keep its marked as tainted flag
	  // try to comment the 3 next lines and switch multiple times the src to see what I mean
	  ctx = canvas.cloneNode(true).getContext('2d');
	  canvas.parentNode.replaceChild(ctx.canvas, canvas);
	  canvas = ctx.canvas;

	  // reset the attributes and error handler
	  img.crossOrigin = 'anonymous';
	  img.onerror = error_handler;
	  img.src = urls[+!urls.indexOf(img.src)];
	};

但是因为toDataURL可能只是一个非常重要的检查而且try catch中的代码被去优化,对于旧浏览器来说,更好的选择是创建一个1px*1px测试器画布,首先在其上绘制图像并在try中调用它的toDataURL -catch块:

var urls = ["http://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png", "http://lorempixel.com/200/200"];

	var img = new Image();
	img.crossOrigin = 'anonymous';

	var canvas = document.createElement('canvas');
	var ctx = canvas.getContext('2d');
	document.body.appendChild(canvas);

	 //create a canvas only for testing if our images will taint our canvas or not;
	var taintTester = document.createElement('canvas').getContext('2d');
	taintTester.width = 1;
	taintTester.height = 1;

	var load_handler = function() {
	  // our image flag
	  var willTaint = false;
	  // first draw on the tester
	  taintTester.drawImage(this, 0, 0);
	  // since it's only one pixel wide, toDataURL is way faster
	  try {
	    taintTester.canvas.toDataURL();
	  } catch (e) {
	    // update our flag
	    willTaint = true;
	  }
	  // it will taint the canvas
	  if (willTaint) {
	    // reset our tester
	    taintTester = taintTester.canvas.cloneNode(1).getContext('2d');


	    // do something
	    ctx.fillStyle = 'rgba(0,0,0,.7)';
	    ctx.fillRect(0, 75, ctx.measureText('we won\'t diplay ' + this.src).width + 40, 60);
	    ctx.fillStyle = 'white';
	    ctx.font = '15px sans-serif';
	    ctx.fillText('we won\'t diplay ' + this.src, 20, 100);
	    ctx.fillText('canvas would have been tainted', 20, 120);
        
	  } else {
        
	    // all clear
	    canvas.width = this.width;
	    canvas.height = this.height;

	    ctx.fillStyle = 'white';
	    ctx.font = '15px sans-serif';

	    ctx.drawImage(this, 0, 0);
	  }
	};

	var error_handler = function() {
	  // remove this onerror listener to avoid an infinite loop
	  this.onerror = function() {
	    return false
	  };

	  // we need to removeAttribute() since chrome doesn't like the property=undefined way...
	  this.removeAttribute('crossorigin');
	  this.src = this.src;
	};

	img.onload = load_handler;
	img.onerror = error_handler;

	img.src = urls[0];

	btn.onclick = function() {
	  // reset the attributes and error handler
	  img.crossOrigin = 'anonymous';
	  img.onerror = error_handler;
	  img.src = urls[+!urls.indexOf(img.src)];
	};

注意

交叉原始请求不是污染画布的唯一方法:
在IE
中存在a,则最新的Safari会对画布进行污染. svg画在画布上,最后,如果画了另一块受污染的画布,任何UA都会污染画布.

因此,在这些情况下检查画布是否被污染的唯一解决方案是try-catch,并且最好是在1px x 1xx测试画布上执行此操作.



1> Kaiido..:

如果crossOrigin浏览器支持属性/属性(现在它在FF,Chrome,最新的Safari和Edge中),但是服务器没有使用正确的标题(Access-Control-Allow-Origin: *)回答,那么img的onerror事件就会触发.

因此,如果我们想要绘制图像,我们可以只处理此事件并删除属性.
对于不处理此属性的浏览器,测试画布是否被污染的唯一方法是调用toDataURLtry catch块.

这是一个例子:

var urls = 
    ["http://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png", 
     "http://lorempixel.com/200/200"];

	var tainted = false;

	var img = new Image();
	img.crossOrigin = 'anonymous';

	var canvas = document.createElement('canvas');
	var ctx = canvas.getContext('2d');
	document.body.appendChild(canvas);

	var load_handler = function() {
	  canvas.width = 200;
	  canvas.height = 200;

	  ctx.fillStyle = 'white';
	  ctx.font = '15px sans-serif';

	  ctx.drawImage(this, 0, 0, 200, 200*(this.height/this.width));

	  // for browsers supporting the crossOrigin attribute
	  if (tainted) {
	    ctx.strokeText('canvas tainted', 20, 100);
	    ctx.fillText('canvas tainted', 20, 100);
	  } else {
	    // for others
	    try {
	      canvas.toDataURL();
	    } catch (e) {
	      tainted = true;
	      ctx.strokeText('canvas tainted after try catch', 20, 100);
	      ctx.fillText('canvas tainted after try catch', 20, 100);
	    }
	  }
	};

	var error_handler = function() {
	  // remove this onerror listener to avoid an infinite loop
	  this.onerror = function() {
	    return false
	  };
	  // certainly that the canvas was tainted
	  tainted = true;

	  // we need to removeAttribute() since chrome doesn't like the property=undefined way...
	  this.removeAttribute('crossorigin');
	  this.src = this.src;
	};

	img.onload = load_handler;
	img.onerror = error_handler;

	img.src = urls[0];

	btn.onclick = function() {
	  // reset the flag
	  tainted = false;

	  // we need to create a new canvas, or it will keep its marked as tainted flag
	  // try to comment the 3 next lines and switch multiple times the src to see what I mean
	  ctx = canvas.cloneNode(true).getContext('2d');
	  canvas.parentNode.replaceChild(ctx.canvas, canvas);
	  canvas = ctx.canvas;

	  // reset the attributes and error handler
	  img.crossOrigin = 'anonymous';
	  img.onerror = error_handler;
	  img.src = urls[+!urls.indexOf(img.src)];
	};

推荐阅读
pan2502851807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有