【问题标题】:Canvas has been tainted by cross-origin data via local chrome:// extension URLCanvas 已通过本地 chrome:// 扩展 URL 被跨域数据污染
【发布时间】:2013-11-22 13:57:23
【问题描述】:

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

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.

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

【问题讨论】:

  • get_url的定义是什么?
  • get_url 是本地实用程序方法,它给我一个 chrome url ala chrome://1238901283908123098190/asset/gotcha.png
  • 你为什么不使用 chrome.extension.getURL() ?上面的代码是从哪里运行的?
  • 代码部署在三个不同的扩展系统/浏览器上,方法会处理不同的资源加载方式。
  • 好的,我只想知道在 Chrome 上它会调用 chrome.extension.getURL()。另一个问题呢:代码从哪里运行(背景页、内容脚本、视图、注入网页)?

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


【解决方案1】:

基于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)}
  );    
}

【讨论】:

  • 一点提示:chrome.extension.onRequest 已弃用。请改用 chrome.runtime.onMessage
  • 设置图片源后也需要“return true”才能异步运行回调developer.chrome.com/extensions/runtime#event-onMessage
  • 在 Chrome 44 中不起作用:Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
【解决方案2】:

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

说明:

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

示例代码:

/* 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"
});

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

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

【讨论】:

    【解决方案3】:

    尝试将您的资产添加到清单文件顶层的 web_accessible_resources 属性,例如

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

    如果你还没有这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-20
      • 2012-01-08
      • 2014-04-01
      • 2020-09-17
      相关资源
      最近更新 更多