如何修复 getImageData ()错误画布已经被跨源数据污染?

我的代码在我的本地主机上运行得很好,但是在站点上不能正常工作。

我从控制台得到了这个错误,对于这一行 .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;
}

注意: my image url (src)来自子域 url

204223 次浏览

您的问题在于加载了一个外部映像,这意味着从另一个域加载。当您尝试访问画布上下文的任何数据时,这将导致安全性错误。

你正在通过从一个跨源域加载来“玷污”画布:

Https://developer.mozilla.org/en-us/docs/html/cors_enabled_image

您不能将图像直接从另一台服务器绘制到画布中,然后使用 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: peps 指出 php 脚本已经暴露,允许互联网恶意使用它。有一百万种方法来处理这个问题,其中最简单的一种是某种 URL 混淆... 我认为安全的 PHP 实践应该有一个单独的谷歌;

Edit-2: 根据流行的需求,我添加了一个检查来确保它是一个图像而不是一个 php 脚本(来自: PHP 检查文件是否为图像)。

正如其他人所说的那样,通过从跨起源域加载,您正在“玷污”画布。

Https://developer.mozilla.org/en-us/docs/html/cors_enabled_image

然而,您可以通过简单地设置:

img.crossOrigin = "Anonymous";

只有当远程服务器适当地设置以下头文件时,这种方法才有效:

Access-Control-Allow-Origin "*"

使用“直接链接”选项时的 Dropbox 文件选择器就是一个很好的例子。我在 Oddprints.com上使用它从远程下拉框图像 URL 中吸取图像到我的画布中,然后将图像数据提交回我的服务器。都是用 javascript 写的

我发现我必须使用 .setAttribute('crossOrigin', ''),并且必须在 URL 的查询字符串中附加一个时间戳,以避免缺少 Access-Control-Allow-Origin标头的304响应。

这给了我

var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');

正如 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)

我今天遇到了同样的问题,并通过下面的代码解决了它。

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')}就可以了

在本地工作时,添加一个服务器。

我在本地工作时也遇到过类似的问题。URL 将成为本地文件的路径,例如 file:///Users/PeterP/Desktop/folder/index.html

请注意,我用的是 Mac。

我通过在全球范围内安装一个 HTTP 服务器来解决这个问题,我使用的是 https://www.npmjs.com/package/http-server

步骤

  1. 全局安装: npm install http-server -g
  2. 运行服务器: http-server ~/Desktop/folder/

这些步骤假设您已经安装了 node,否则运行 npm命令不会有多远的距离。

当我在本地测试我的代码时,我在 Chrome上看到了这个错误。我切换到 Firefox,我不再看到错误。也许切换到另一个浏览器是一个快速解决方案。

如果您正在使用第一个答案中给出的解决方案,那么请确保在声明 img变量(例如。var img = new Image();).

我的问题是如此混乱,我只是 base64编码的图像,以确保不会有任何 CORS 问题

当使用图像源代替实际的图像源时,您可以将图像转换为数据字符串。

[ https://www.base64-image.de/][1]将图像转换为数据字符串。 从上述网站转换和复制字符串数据。 Src = < copy _ data _ string > 设置 image. src = < copy _ 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)

没有画布的跨原点依赖

ImagecrossOrigin属性设置为 Anonymous

  let image = new Image();
// image.src = ...;
image.crossOrigin = `Anonymous`;