Canvas has been tainted by cross-origin data via local chrome:// extension URL Canvas has been tainted by cross-origin data via local chrome:// extension URL google-chrome google-chrome

Canvas has been tainted by cross-origin data via local chrome:// extension URL


Based on ExpertSystem's approach I got a simple solution.

First part in the JavaScript of the background page where a canvas can be created without throwing a security exception.

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()    }  })

Second part for the content script:

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


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:

Description:

  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.:

  • 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.


Try to add your assets to the web_accessible_resources property at the top-level of your manifest file, e.g.

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

if you have not done so yet.