基本情景
我在客户端加载了几张图片。其中一些来自另一个域,有些则不是。有些我可以使用crossOrigin
attribute访问,有些则无法访问。
基本要求是尽可能为图像检索dataURL。
问题
将图像绘制到canvas元素后(我需要获取dataURL,对吗?),如何在没有try ... catch
块的情况下检查画布是否已被污染< / em>的?如果画布受到污染,我将无法再使用toDataURL()
(see MDN)。
var image = new Image(),
canvas = document.createElement( 'canvas' ),
context = canvas.getContext( '2d' );
image.onload = function(){
// adjust dimensions of canvas
canvas.width = image.width;
canvas.height = image.height;
// insert image
context.drawImage( image, 0, 0 );
// how to check here?
// get dataurl
dataurl = tmpCanvas.toDataURL();
// do stuff with the dataurl
};
image.src = src; // some cross origin image
答案 0 :(得分:4)
这是一个不向本机对象添加属性的解决方案:
function isTainted(ctx) {
try {
var pixel = ctx.getImageData(0, 0, 1, 1);
return false;
} catch(err) {
return (err.code === 18);
}
}
现在只需检查:
if (isTainted(ctx)) alert('Sorry, canvas is tainted!');
编辑:现在我看到你想要一个没有try-catch的解决方案。但是,这是检查的正确方法,因为没有向用户公开的原始清洁标志(它仅供内部使用)。将属性添加到本机对象不建议。
答案 1 :(得分:1)
这是对没有使用try-catch的CORS污染的间接测试:
演示:http://jsfiddle.net/m1erickson/uDt2K/
它的工作原理是在加载图像之前设置image.tainted=true
标志
然后在image.onload中,context.getImageData
触发/不会触发CORS违规。
如果没有发生违规,则污点标志设置为假(image.tainted=false
)。
var img=new Image();
// set a "tainted flag to the image to true (initialize as tainted)
img.tainted=true;
img.onload=function(){
// try an action that triggers CORS security
var i=ctx.getImageData(1,1,1,1);
// if we don't get here, we violated CORS and "tainted" remains true
// if we get here, CORS is happy so set the "tainted" flag to false
img.tainted=false;
};
// test with tainted image
img.src="http://pp-group.co.uk/wp/wp-content/uploads/2013/10/house-illustration-web.gif";
由于image.onload是异步的,因此即使在CORS违规后,image.onload外部的代码仍会执行。
以下示例代码:
示例代码:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
// known CORS violator
var src1="http://pp-group.co.uk/wp/wp-content/uploads/2013/10/house-illustration-web.gif";
// known CORS compliant
var src2="https://dl.dropboxusercontent.com/u/139992952/houseIcon.png";
// callbacks depending on if the image causes tainted canvas
function tainted(img){console.log("tainted:",img.src);}
function notTainted(img){console.log("not tainted:",img.src);}
// testing
var image1=newImage(src1,tainted,notTainted);
var image2=newImage(src2,tainted,notTainted);
function newImage(src,callWhenTainted,callWhenNotTainted){
// tmpCanvas to test CORS
var tmpCanvas=document.createElement("canvas");
var tmpCtx=tmpCanvas.getContext("2d");
// tmpCanvas just tests CORS, so make it 1x1px
tmpCanvas.width=tmpCanvas.height=1;
var img=new Image();
// set the cross origin flag (and cross our fingers!)
img.crossOrigin="anonymous";
img.onload=function(){
// add a tainted property to the image
// (initialize it to true--is tainted)
img.tainted=true;
// draw the img on the temp canvas
tmpCtx.drawImage(img,0,0);
// just in case this onload stops on a CORS error...
// set a timer to call afterOnLoad shortly
setTimeout(function(){
afterOnLoad(img,callWhenTainted,callWhenNotTainted);
},1000); // you can probably use less than 1000ms
// try to violate CORS
var i=tmpCtx.getImageData(1,1,1,1);
// if we get here, CORS is OK so set tainted=false
img.tainted=false;
};
img.src=src;
return(img);
}
// called from image.onload
// at this point the img.tainted flag is correct
function afterOnLoad(img,callWhenTainted,callWhenOK){
if(img.tainted){
// it's tainted
callWhenTainted(img);
}else{
// it's OK, do dataURL stuff
callWhenOK(img);
}
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=360 height=281></canvas>
</body>
</html>