Canvas已被跨原始数据通过本地chrome://扩展网址污染

问题描述:

我正在使用Google Chrome扩展程序,我试图将与扩展程序捆绑在一起的图像加载到画布上。

I am working on a google chrome extension and I am trying to load an image that is bundled with the extension into a canvas.

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");

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

When I execute the code in a content script I am getting:

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

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

Is there a way to avoid this? I have successfully embedded images, audio, video and flash directly into target sites without any those issues. The resource is listed under the web_accessible_resources in the manifest file.

您无法直接将图片从扩展程序传递到

这是一种解决方法:

You can't directly pass an image from your extension to a web-page's canvas without making it tainted.
This is a work-around:

说明:


  1. 您可以从背景页面(或内容脚本)访问图片。


  2. 将注入的代码插入到网页中,并将dataURL作为字符串传递。
  3. 使用字符串(dataURL)创建图像(在网页的上下文中)并将其绘制到画布上。
  1. You access the image from your background page (or content script).
  2. You put it in a canvas and convert it to a dataURL.
  3. You inject some JS code into the web-page, passing the dataURL as a string.
  4. The injected code uses the string (dataURL) to create an image (in the context of the web-page) and draw it onto a canvas.

示例代码

Sample code:

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

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

This is a more generic approach (that can be used by any content script with minimum configuration), but it might be simpler to move part of the logic to the content script. E.g.:


  • 在内容脚本中定义一个函数,使用dataURL调用时,会创建图片并将其绘制到画布上。

  • 在后台页面中定义一个函数,该函数需要一个图像路径并返回一个dataURL(如上所示)。

  • 使用 chrome.runtime .getBackgroundPage()来获取对后台页面对象的引用,调用该函数将图像路径转换为dataURL,最后使用该数据URL创建图像并将其绘制到画布上。

  • Define a function within the content script, that when called with a dataURL creates and draws an image onto a canvas.
  • Define a function in the background page, that takes an image-path and returns a dataURL (as seen above).
  • Use chrome.runtime.getBackgroundPage() to get a reference to the background page's window object, call the function to convert an image-path to a dataURL and finally use that dataURL to create an image and draw it onto a canvas.