我的代码在本地主机上运行得很好,但在站点上不起作用。
我从控制台得到了这个错误,对于这行.getImageData(x,y,1,1).data
:
Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
我代码的一部分:
jQuery.Event.prototype.rgb=function(){
var x = this.offsetX || (this.pageX - $(this.target).offset().left),y = this.offsetY || (this.pageY - $(this.target).offset().top);
if (this.target.nodeName!=="CANVAS")return null;
return this.target.getContext('2d').getImageData(x,y,1,1).data;
}
注意:我的图像url(src)来自子域url
正如其他人所说,您通过从跨源域加载来"污染"画布。
https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image
然而,您可以通过简单设置来防止这种情况:
img.crossOrigin = "Anonymous";
只有当远程服务器正确设置以下标头时,这才有效:
Access-Control-Allow-Origin "*"
使用"直接链接"选项时的Dropbox文件选择器就是一个很好的例子。我在oddprints.com上使用它将远程dropbox图像url中的图像收集到我的画布中,然后将图像数据提交回我的服务器。全部在javascript 中
我发现我必须使用.setAttribute('crossOrigin', '')
,并且必须在URL的查询字符串中附加一个时间戳,以避免304响应缺少Access-Control-Allow-Origin
标头。
这给了我
var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');
您将无法直接从另一台服务器将图像绘制到画布中,然后使用getImageData
。这是一个安全问题,画布将被视为"污点"。
使用PHP将图像的副本保存到服务器,然后只加载新图像,这对你有用吗?例如,您可以将URL发送到PHP脚本并将其保存到服务器,然后将新文件名返回到您的javascript,如下所示:
<?php //The name of this file in this example is imgdata.php
$url=$_GET['url'];
// prevent hackers from uploading PHP scripts and pwning your system
if(!@is_array(getimagesize($url))){
echo "path/to/placeholderImage.png";
exit("wrong file type.");
}
$img = file_get_contents($url);
$fn = substr(strrchr($url, "/"), 1);
file_put_contents($fn,$img);
echo $fn;
?>
您可以将PHP脚本与一些ajax javascript一起使用,例如:
xi=new XMLHttpRequest();
xi.open("GET","imgdata.php?url="+yourImageURL,true);
xi.send();
xi.onreadystatechange=function() {
if(xi.readyState==4 && xi.status==200) {
img=new Image;
img.onload=function(){
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
}
img.src=xi.responseText;
}
}
如果之后在画布上使用getImageData
,它将正常工作。
或者,如果你不想保存整个图像,你可以通过x&y坐标到PHP脚本,并计算该侧像素的rgba值。我认为有很好的库可以在PHP中进行这种图像处理。
如果你想使用这种方法,如果你需要帮助实现它,请告诉我
edit-1:peeps指出php脚本被暴露,并允许互联网恶意使用它。有一百万种方法可以处理这个问题,其中最简单的是某种URL混淆。。。我认为安全的php实践应该有一个单独的谷歌;P
edit-2:根据流行的需求,我添加了一个检查,以确保它是一个图像而不是php脚本(来自:php检查文件是否是图像)。
当我在本地测试代码时,我在Chrome
上看到了这个错误。我切换到Firefox
,不再看到错误。也许切换到另一个浏览器是一个快速解决方案。
如果您使用的是第一个答案中给出的解决方案,请确保在声明img
变量(例如var img = new Image();
)之后添加img.crossOrigin = "Anonymous";
。
在本地工作时,添加一个服务器
我在本地工作时也遇到过类似的问题。您的URL将是本地文件的路径,例如file:///Users/PeterP/Desktop/folder/index.html
。
请注意,我在Mac电脑上。
我通过在全球范围内安装HTTP服务器来解决这个问题。我曾经https://www.npmjs.com/package/http-server
步骤
- 全局安装:
npm install http-server -g
- 运行服务器:
http-server ~/Desktop/folder/
这些步骤假设您已经安装了node
,否则运行npm
命令就不会太远。
我的问题太糟糕了,我只对图像进行了base64编码,以确保不会出现任何CORS问题
您的问题是加载外部映像,即从另一个域加载映像。当您尝试访问画布上下文的任何数据时,这会导致安全错误。
您通过从跨原点域加载来"污染"画布。查看这篇MDN文章:
https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image
将Image
的crossOrigin
属性设置为Anonymous
。
let image = new Image();
// image.src = ...;
image.crossOrigin = `Anonymous`;
正如matt burns在回答中所说,您可能需要在托管问题图像的服务器上启用CORS。
如果服务器是Apache,可以通过将以下代码段(从这里)添加到VirtualHost配置或.htaccess
文件来完成:
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
<FilesMatch ".(cur|gif|ico|jpe?g|png|svgz?|webp)$">
SetEnvIf Origin ":" IS_CORS
Header set Access-Control-Allow-Origin "*" env=IS_CORS
</FilesMatch>
</IfModule>
</IfModule>
如果将其添加到VirtualHost,您可能也需要重新加载Apache的配置(例如,如果Apache在Linux服务器上运行,则为sudo service apache2 reload
)
您可以将图像转换为数据字符串,因为使用图像源而不是实际的图像源。
[https://www.base64-image.de/][1] 将图像转换为数据字符串。转换并复制上述网站的字符串数据。set image.src=<copied_data_string>。
解决方案,将源图像URL转换为Base64数据并分配给img
例如,使用Axios
const getBase64 = async(url)=>{
try {
let image = await axios.get(url, { responseType: 'arraybuffer' });
let raw = Buffer.from(image.data).toString('base64');
return "data:" + image.headers["content-type"] + ";base64,"+raw;
} catch (error) {
console.log(error)
}
}
var image = new Image()
image.src=getBase64(url)
画布没有跨来源依赖
我今天遇到了同样的问题,并通过下面的代码解决了它。
html代码:
<div style='display: none'>
<img id='img' src='img/iak.png' width='600' height='400' />
</div>
<canvas id='iak'>broswer don't support canvas</canvas>
js代码:
var canvas = document.getElementById('iak')
var iakImg = document.getElementById('img')
var ctx = canvas.getContext('2d')
var image = new Image()
image.src=iakImg.src
image.onload = function () {
ctx.drawImage(image,0,0)
var data = ctx.getImageData(0,0,600,400)
}
代码如上,不存在跨域问题。
我遇到了同样的问题,对我来说,它只是通过连接https:${image.getAttribute('src')}
来工作