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

Erf*_*oor 117 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. 
Run Code Online (Sandbox Code Playgroud)

我的部分代码:

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;
    }
Run Code Online (Sandbox Code Playgroud)

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

mat*_*rns 98

正如其他人所说的那样,你通过从一个交叉起源域加载来"污染"画布.

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

但是,您可以通过简单设置来阻止这种情况:

img.crossOrigin = "Anonymous";
Run Code Online (Sandbox Code Playgroud)

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

Access-Control-Allow-Origin "*"
Run Code Online (Sandbox Code Playgroud)

The Dropbox file chooser when using the "direct link" option is a great example of this. I use it on oddprints.com to hoover up images from the remote dropbox image url, into my canvas, and then submit the image data back into my server. All in javascript :)

  • 如果它是本地文件,而您的应用根本不使用互联网怎么办?就像 android webview 应用程序一样,图像与 html 文件位于同一文件夹中。这解决不了。 (4认同)
  • 如果我先放置 crossorigin 然后设置源然后访问数据 onload 对我有用 (3认同)

Kir*_*rby 39

我发现我必须使用.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', '');
Run Code Online (Sandbox Code Playgroud)

  • 在本地文件上没有服务器的情况下尝试此操作会给出:在来自'null'的'file:/// C:/.../img/colorPaletteCtrl.png?1507058959277'中访问Image已被CORS策略阻止:响应无效.因此不允许原点'null'访问. (3认同)

jay*_*aya 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;

?>
Run Code Online (Sandbox Code Playgroud)

你将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;
  }
}
Run Code Online (Sandbox Code Playgroud)

如果你getImageData之后在画布上使用它,它将正常工作.

或者,如果您不想保存整个图像,可以将x和y坐标传递给PHP脚本并计算该侧的像素rgba值.我认为在PHP中进行这种图像处理有很好的库.

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

  • 另外 - 从本地文件系统加载图像和脚本,也会出现同样的问题. (15认同)
  • 这不是很安全,有人可能会使用php脚本恶意地用大文件淹没您的服务器,这将是不好的 (2认同)
  • 您需要验证用户提供的上传文件名、文件/mime 类型、位置和大小。该代码容易受到多种攻击。我将把它作为练习留给读者,但我相信可以使用此代码将 .php 文件上传到网络服务器的根目录。 (2认同)

小智 6

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

我在本地工作时遇到了类似的问题。您的 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命令。


bum*_*ard 6

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


Saf*_*wan 5

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

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


axe*_*uch 2

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