如何修复getImageData()错误画布受到跨源数据的污染?

时间:2014-02-28 14:22:55

标签: javascript html5 html5-canvas

我的代码在我的localhost上工作得非常好,但它不能在网站上运行。

我从控制台收到此错误,此行.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;
    }

注意:我的图片网址(src)来自子网址

14 个答案:

答案 0 :(得分:85)

正如其他人所说,你已经"污染"通过从交叉起源域加载画布。

https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image

但是,您可以通过简单地设置:

来防止这种情况发生
img.crossOrigin = "Anonymous";

仅当远程服务器正确设置以下标头时才有效:

Access-Control-Allow-Origin "*"

Dropbox file chooser使用"直接链接"选项就是一个很好的例子。我在oddprints.com上使用它将远程保管箱图像网址中的图像保存到我的画布中,然后将图像数据提交回我的服务器。全部用javascript

答案 1 :(得分:34)

我发现我必须使用.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', '');

答案 2 :(得分:17)

您将无法直接从其他服务器将图像绘制到画布中,然后使用getImageData。这是一个安全问题,画布将被视为“污点”。

您是否可以使用PHP将图像副本保存到服务器,然后只加载新图像?例如,您可以将URL发送到PHP脚本并将其保存到您的服务器,然后将新文件名返回到您的javascript,如下所示:

<?php //The name of this file in this example is imgdata.php

  $url=$_GET['url'];
  $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&amp; y坐标到PHP脚本并计算该侧的像素rgba值。我认为在PHP中进行这种图像处理有很好的库。

如果您想使用此方法,请告诉我您是否需要帮助实施它。

编辑:peeps指出php脚本已暴露并允许互联网恶意使用它。有一百万种方法可以解决这个问题,其中一种最简单的方法是某种URL混淆...我认为安全的PHP实践值得一个单独的谷歌; P

答案 3 :(得分:2)

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

答案 4 :(得分:2)

您通过从跨源域加载来“污染”画布。看看这篇MDN文章:

https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image

答案 5 :(得分:2)

在本地测试代码时,我在Chrome上看到此错误。我切换到Firefox,但再也看不到错误了。也许切换到其他浏览器是一种快速解决方案。

如果您使用的是第一个答案中给出的解决方案,请确保在声明img.crossOrigin = "Anonymous";变量之后添加img(例如var img = new Image();)。

答案 6 :(得分:0)

正如亚光烧伤在his answer中所说,您可能需要在托管问题图像的服务器上启用CORS。

如果服务器是Apache,可以通过将以下代码段(从here)添加到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的配置(例如。sudo service apache2 reload如果Apache在Linux服务器上运行)< / p>

答案 7 :(得分:0)

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

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

请注意,我在使用MAC。

我通过全局安装http-server来解决这个问题。 https://www.npmjs.com/package/http-server

步骤:

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

PS:我假设您已经安装了节点,否则您将无法获得运行得很远的npm命令。

答案 8 :(得分:0)

我(非常简单)使用https://www.base64-image.de/将我的图片转换为基本的64个文件。然后,我只是用该(非常长的)图像代码字符串替换了对文件路径的调用。

答案 9 :(得分:0)

我的问题太混乱了,我只对图像进行了base64编码,以确保不会出现任何CORS问题

答案 10 :(得分:0)

您可以使用图像源而不是实际图像源将图像转换为数据字符串。

[https://www.base64-image.de/][1] 将图像转换为数据字符串。 从上述网站转换和复制字符串数据。 设置 image.src = .

答案 11 :(得分:0)

解决方法, 将源图像 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)

没有来自画布的跨源依赖

答案 12 :(得分:-1)

我今天遇到同样的问题,并按照以下代码解决。

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 code:

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

代码如上所述,并且没有跨域问题。

答案 13 :(得分:-2)

我遇到了同样的问题,对我来说,只需将https:${image.getAttribute('src')}串联起来就可以了