gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 15:31:52 28 4
gpt4 key购买 nike

所以我正在尝试为我正在构建的 OpenLayers 3 应用程序创建打印 map 功能。我知道他们的 example但每当我尝试使用它时,我都会遇到可怕的受污染 Canvas 问题。我已经阅读了整个互联网并遇到了一些人说首先要正确设置 CORS(完成和完成)但也要这样做:

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

以上是描述here .

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

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

有什么想法吗?

我看过this .我的问题是他们如何将其整合到有效的功能中。像这样的东西:

    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);
};
};

最佳答案

如果浏览器支持 crossOrigin 属性/属性(它现在在 FF、Chrome、最新的 Safari 和 Edge 中),但服务器没有使用正确的 header 进行响应 ( Access-Control-Allow-Origin: * ),然后将触发 img 的 onerror 事件。

所以如果我们想绘制图像,我们可以只处理这个事件并删除该属性。
对于不处理此属性的浏览器,测试 Canvas 是否被污染的唯一方法是将 toDataURL 调用到 try catch block 中。

这是一个例子:

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)];
};
<button id="btn"> change image src </button><br>

但由于 toDataURL 可能是一个非常繁重的检查调用,并且 try catch 中的代码被取消优化,对于旧版浏览器,更好的替代方法是创建一个 1px*1px 测试 Canvas ,首先在其上绘制图像并调用它toDataURL 在 try-catch block 中:

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)];
};
<button id="btn">change image src</button>

注意

跨源请求并不是污染 Canvas 的唯一方法:
在 IE < Edge 中,在 Canvas 上绘制 svg 会因安全问题污染 Canvas ,同样,如果在 Canvas 上绘制的 svg 中存在 <foreignObject>,最新的 Safari 确实会污染 Canvas ,最后,任何 UA 都会污染 Canvas canvas 如果在其上绘制了其他受污染的 Canvas 。

因此在这些情况下检查 Canvas 是否被污染的唯一解决方案是 try-catch ,最好是在 1px x 1px 测试 Canvas 上这样做。

关于javascript - 使用 canvas.toDataURL 时如何设置 crossOrigin 属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34639708/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com