Canvas был испорчен данными из разных источников через локальный URL-адрес chrome://

Я работаю над расширением 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.

Есть ли способ избежать этого? Я успешно внедрил изображения, аудио, видео и флеш прямо в целевые сайты без каких-либо проблем. Ресурс указан под web_accessible_resources в файле манифеста.

3 ответа

Решение

Вы не можете напрямую передать изображение с вашего расширения на холст веб-страницы, не сделав его испорченным.
Это обходной путь:

Описание:

  1. Вы получаете доступ к изображению с фоновой страницы (или сценария содержимого).
  2. Вы помещаете это в canvas и конвертируете в 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, чтобы создать изображение и нарисовать его на холсте.

На основе подхода ExpertSystem я получил простое решение.

Первая часть в 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)}
  );    
}

Попробуйте добавить свои активы в web_accessible_resources свойство на верхнем уровне вашего файла манифеста, например

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

если вы еще этого не сделали.

Другие вопросы по тегам