Canvas受到本地chrome://扩展URL的跨源数据的污染

时间:2013-11-10 20:44:43

标签: javascript google-chrome canvas google-chrome-extension webgl

我正在开发一个谷歌浏览器扩展程序,我正在尝试将与扩展程序捆绑在一起的图像加载到画布中。

var canvas = document.createElement('canvas');
canvas.width = 470;
canvas.height = 470;
var context = canvas.getContext('2d');
var image = new Image();
image.addEventListener('load', function(){
     //process
});
image.src = chrome.extension.getURL("asset/gotcha.png");

当我在内容脚本中执行代码时,我得到了:

Unable to get image data from canvas because the canvas has been  tainted by 
cross-origin data.

有没有办法避免这种情况?我已经成功地将图像,音频,视频和闪存直接嵌入到目标站点中而没有任何问题。资源列在清单文件中的web_accessible_resources下。

3 个答案:

答案 0 :(得分:6)

基于ExpertSystem's approach我得到了一个简单的解决方案。

后台页面的JavaScript的第一部分,可以在不抛出安全性异常的情况下创建画布。

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.message == "convert_image_url_to_data_url") {
      var canvas = document.createElement("canvas");
      var img = new Image();
      img.addEventListener("load", function() {
        canvas.getContext("2d").drawImage(img, 0, 0);
        sendResponse({data: canvas.toDataURL()}); 
      });
      img.src = request.url;
      return true; // Required for async sendResponse()
    }
  }
)

内容脚本的第二部分:

//@success is the callback
function local_url_to_data_url(url, success) {  
  chrome.runtime.sendMessage(
    {message: "convert_image_url_to_data_url", url: url}, 
    function(response) {success(response.data)}
  );    
}

答案 1 :(得分:4)

您不能直接将图片从您的扩展程序传递到网页的画布而不会使其受到污染 这是一个解决方法:

说明

  1. 您可以从后台页面(或内容脚本)访问图像。
  2. 您将它放在画布中并将其转换为dataURL。
  3. 您将一些JS代码注入网页,并将dataURL作为字符串传递。
  4. 注入的代码使用字符串(dataURL)创建图像(在网页的上下文中)并将其绘制到画布上。
  5. 示例代码:

    /* In `background.js` */
    function injectImg(tabID, remoteCanvasID, imgPath) {
        var canvas = document.createElement("canvas");
        var img = new Image();
        img.addEventListener("load", function() {
            canvas.getContext("2d").drawImage(img, 0, 0);
            var dataURL = canvas.toDataURL();
            var code = [
                "(function() {",
                "    var canvas = document.getElementById(\"" + remoteCanvasID + "\");",
                "    var img = new Image();",
                "    img.addEventListener(\"load\", function() {",
                "        canvas.getContext(\"2d\").drawImage(img, 0, 0);",
                "    });",
                "    img.src = \"" + dataURL + "\";",
                "    ",
                "})();"].join("\n");
            chrome.tabs.executeScript(tabID, { code: code });
        });
        img.src = chrome.extension.getURL(imgPath);
    }
    
    chrome.runtime.onMessage.addListener(function(msg, sender)) {
        if (msg.action && (msg.action == "getImg")
                && msg.imgPath && msg.canvasID) {
            injectImg(sender.tab.id, msg.canvasID, msg.imgPath);
        }
    });
    
    /* In `content.js` */
    chrome.runtime.sendMessage({
        action: "getImg",
        imgPath: "some/image.png",
        canvasID: "someCanvasID"
    });
    

    这是一种更通用的方法(可以由具有最小配置的任何内容脚本使用),但将部分逻辑移动到内容脚本可能更简单。 E.g:

    • 在内容脚本中定义一个函数,当使用dataURL调用时,会在画布上创建并绘制图像。
    • 在后台页面中定义一个函数,它接受一个图像路径并返回一个dataURL(如上所示)。
    • 使用 chrome.runtime.getBackgroundPage()获取对后台页面的window对象的引用,调用函数将image-path转换为dataURL,最后使用该dataURL创建一个图像并将其绘制到画布上。

答案 2 :(得分:2)

尝试将您的资源添加到清单文件顶层的web_accessible_resources媒体资源中,例如

    "web_accessible_resources": ["asset/gotcha.png"],

如果你还没有这样做的话。