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

Javascript 如何修复getImageData()错误画布已被跨源数据污染?,javascript,html,html5-canvas,Javascript,Html,Html5 Canvas,我的代码在本地主机上运行得很好,但在站点上不起作用 我从控制台得到这一错误,这一行是。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=func

我的代码在本地主机上运行得很好,但在站点上不起作用

我从控制台得到这一错误,这一行是
。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

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

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


您将无法直接从另一台服务器将图像绘制到画布中,然后使用
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;

?>
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实践应该有一个单独的google;P


编辑-2:根据流行的需求,我添加了一个检查,以确保它是一个图像而不是一个php脚本(from:)。

正如其他人所说,通过从跨源域加载,您正在“污染”画布

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

img.crossOrigin = "Anonymous";
这仅在远程服务器正确设置以下标头时有效:

Access-Control-Allow-Origin "*"

当使用“直接链接”选项时,就是一个很好的例子。我使用它将远程dropbox图像url中的图像收集到画布中,然后将图像数据提交回服务器。在javascript中,我发现我必须使用
.setAttribute('crossOrigin','')
,并且必须在URL的查询字符串中附加一个时间戳,以避免缺少
访问控制允许来源
头的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>

SetEnvIf原点“:”是
标题集访问控制允许原点“*”env=IS\u CORS

…如果将其添加到VirtualHost中,您可能也需要重新加载Apache的配置(例如,如果Apache在Linux服务器上运行,则重新加载sudo service apache2)

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

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>

类似于上面的代码,没有跨域问题。

我也遇到了同样的问题,对我来说,在本地添加服务器时,它通过简单地连接https:${image.getAttribute('src')}

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

请注意,我使用的是MAC电脑。

我通过在全球范围内安装http服务器解决了这个问题

步骤:

  • 全局安装:
    npm安装http服务器-g
  • 运行服务器:
    http服务器~/Desktop/folder/

  • PS:我假设你已经安装了node,否则你运行npm命令就走不了多远。

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


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

    我的问题非常糟糕,我只对图像进行了base64编码,以确保不会出现任何CORS问题。

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

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

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

    没有来自画布的跨源依赖关系

    是的,我从上载子域获取图像。。。我该怎么办?你可以使用一个代理来检索你的图像,这个代理将与你运行画布的域位于同一个域上。我正在从我的计算机上载新图像并尝试将其加载到画布中,我收到了这个错误。我没有使用任何类型的服务器映像。脚本所在(但未执行)的服务器会将您的计算机视为外部域,因为复制到画布中的映像是在您的计算机上创建的,脚本实际上是在您的计算机上执行的。我添加了setenif Origin:“IS_CORS Header set Access Control Allow Origin“*”env=IS_CORS to htaccess all domains但不工作!你在测试什么浏览器?确保你重新启动了Apache。我无法重新启动Apache。。。我有share cpanel帐户。抱歉,无法帮助您配置Apache设置。这也超出了这个问题的范围。张贴您关于Apach的问题
    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)