Javascript 从浏览器扩展(vs CORS)访问图像和视频数据

Javascript 从浏览器扩展(vs CORS)访问图像和视频数据,javascript,html,google-chrome-extension,cors,browser-extension,Javascript,Html,Google Chrome Extension,Cors,Browser Extension,我正在尝试编写一个浏览器扩展,它可以进行一些图像处理,但我需要访问图像数据。我的方法是创建一个隐藏的画布元素,通过drawImage向其绘制图像和视频,然后使用getImageData读取像素数据。这很好,但在许多页面上,一半的内容被CORS错误拒绝 我仍然对CORS存在的原因感到困惑(有些东西是不窃取数据的,但是如果数据在客户的计算机上,它不是已经“被盗”了吗?:s)。它似乎只会导致像JS脚本注入这样的迟钝的黑客行为。所以1。它不起作用,因为它太复杂了,以至于每个浏览器都无法正确监控。开发人员

我正在尝试编写一个浏览器扩展,它可以进行一些图像处理,但我需要访问图像数据。我的方法是创建一个隐藏的画布元素,通过
drawImage
向其绘制图像和视频,然后使用
getImageData
读取像素数据。这很好,但在许多页面上,一半的内容被CORS错误拒绝

我仍然对CORS存在的原因感到困惑(有些东西是不窃取数据的,但是如果数据在客户的计算机上,它不是已经“被盗”了吗?:s)。它似乎只会导致像JS脚本注入这样的迟钝的黑客行为。所以1。它不起作用,因为它太复杂了,以至于每个浏览器都无法正确监控。开发人员受到惩罚,必须编写特定于浏览器的变通方法。所以我想我一定是弄错了,因为这看起来很愚蠢

退一步说,我认为可以做一些图像处理的扩展的想法是完全正常的,不是恶意的,因此请不要回答“不,出于安全原因,您不应该这样做”

我怀疑浏览器将扩展视为外来的东西,可能试图进行恶意操作我如何才能向浏览器保证客户端需要这些功能,并让它允许我访问图像和视频内容?我已经拥有对DOM的完全访问权限,一点点额外的功能会有什么不同


是否有其他方法可以从扩展名获取图像/视频数据?

向清单文件添加正确的权限后,您可以像处理跨源数据一样处理跨源数据,而不受同一源策略的阻碍。在扩展过程中的一个或任何其他页面中,您可以获得所述逻辑的工作演示,如下所示:

// background.js
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var image = document.createElement('img');
image.onload = function() {
    context.drawImage(image, 0, 0);
    // Demo: Show image
    window.open(canvas.toDataURL('image/png'));
};
image.src = 'https://stackoverflow.com/favicon.ico';
以下是此特定演示的最小清单文件:

{
    "name": "Get image data",
    "version": "1",
    "manifest_version": 2,
    "background": {
        "scripts": ["background.js"]
    },
    "permissions": [
        "https://stackoverflow.com/favicon.ico",
        "http://cdn.sstatic.net/stackoverflow/img/favicon.ico"
    ]
}
第二个权限是必需的,因为重定向到

请注意,由于DOM是共享的,Chrome无法仅提供对内容脚本的无限制源访问,因此代码不在中工作

根据您真正想要的,您也可以尝试使用
XMLHttpRequest
以原始形式获取图像数据,并以您想要的任何方式处理它。此方法也适用于内容脚本,其优点是效率更高,并且还保留了图像的字节(使用canvas方法,图像在转换为数据URL之前由浏览器进行解析和处理)


解决这个问题的一个办法是使用Chrome的
desktopCapture
功能。 注意,这意味着用户必须在每次想要录制时与请求权限的弹出窗口进行交互(这可能会保留很长时间,但我想这不是很节省资源)

如果有帮助的话,我会把代码放在这里

background.js

var pending_request_id = null;

var video = document.createElement('video');
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
var theStream = null;

var CAPTURING = false;

/*
 * Setting up recording when the user clicks the extension icon
 */
chrome.browserAction.onClicked.addListener(function() {
  if (CAPTURING) {
    console.log('stop capturing');
    theStream.getVideoTracks()[0].stop();
    chrome.browserAction.setIcon({path: "icons/icon128.png"});
    CAPTURING = false;
  } else {
    pending_request_id = chrome.desktopCapture.chooseDesktopMedia(
      ["screen","tab"],
      onAccessApproved
    );
  }
});

function onAccessApproved(id) {
  console.log('onAccessApproved: ' +id)
  if (!id) {
    console.log("Access rejected.");
    return;
  }
  navigator.webkitGetUserMedia({
    audio:false,
    video: {
      mandatory: {
        chromeMediaSource: "desktop",
        chromeMediaSourceId: id,
        maxWidth: 4000,
        maxHeight: 4000
      }
    }
  }, gotStream, getUserMediaError);
}

function getUserMediaError(error) {
  console.log("getUserMedia() failed:", error);
}

function gotStream(stream) {
  console.log("gotStream", stream);
  theStream = stream;
  video.src = URL.createObjectURL(theStream);
  video.play();
}

video.addEventListener('loadedmetadata',function(){
  console.log('loadedmetadata')
  chrome.browserAction.setIcon({path: "icons/icon128_recording.png"});
  CAPTURING = true;
}, false);


/*
 * You can trigger this when you want; I am doing it on every mouse move over the video (triggered by the content_script.js)
 */
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (!CAPTURING) {
      console.log('User needs to activate the recording of the screen')
      return false; // no response
    }

    ctx.drawImage(video, 0, 0);
    var url = canvas.toDataURL('image/png');
    window.open(url);
  }
);

在内容脚本中,还是从背景页?@RobW我只想知道任何直接的方法。我不知道这可以从背景页上完成。如何访问每个页面中的图像/视频数据?@jozxyqk您是否找到了从用户正在观看的视频中获取数据的解决方案?我遇到了与您相同的问题,我甚至想不出在后台加载视频的方法,因为youtube视频使用了
src=“blob:…”
属性。@krookedking有时会有帮助,但如果没有,我还没有看到其他方法。@jozxyqk好的,谢谢你的指针!事实上,我已经找到了一种实现我想要的东西的不同方式,使用chrome的
desktopCapture
功能。。。非常夸张,但是做得很好。谢谢你这么详细的回答!第一种方法对我来说似乎不可能,因为我需要添加用户将浏览到权限的所有图像/视频。第二种方法不会遇到CORS问题吗?如果是这样的话,为什么要拒绝访问DOM映像呢?这对于图像来说非常好,但视频仍然是一个问题,因为我必须将我的副本与页面中播放的副本同步。这两种方法都需要主机权限。如果您想访问所有http(s)站点,只需使用
*://*/*
作为权限即可。CORS不是一个问题,而是一个绕过限制的解决方案。感谢@RobW指出代码必须放在background.js中。它对我有用
var pending_request_id = null;

var video = document.createElement('video');
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
var theStream = null;

var CAPTURING = false;

/*
 * Setting up recording when the user clicks the extension icon
 */
chrome.browserAction.onClicked.addListener(function() {
  if (CAPTURING) {
    console.log('stop capturing');
    theStream.getVideoTracks()[0].stop();
    chrome.browserAction.setIcon({path: "icons/icon128.png"});
    CAPTURING = false;
  } else {
    pending_request_id = chrome.desktopCapture.chooseDesktopMedia(
      ["screen","tab"],
      onAccessApproved
    );
  }
});

function onAccessApproved(id) {
  console.log('onAccessApproved: ' +id)
  if (!id) {
    console.log("Access rejected.");
    return;
  }
  navigator.webkitGetUserMedia({
    audio:false,
    video: {
      mandatory: {
        chromeMediaSource: "desktop",
        chromeMediaSourceId: id,
        maxWidth: 4000,
        maxHeight: 4000
      }
    }
  }, gotStream, getUserMediaError);
}

function getUserMediaError(error) {
  console.log("getUserMedia() failed:", error);
}

function gotStream(stream) {
  console.log("gotStream", stream);
  theStream = stream;
  video.src = URL.createObjectURL(theStream);
  video.play();
}

video.addEventListener('loadedmetadata',function(){
  console.log('loadedmetadata')
  chrome.browserAction.setIcon({path: "icons/icon128_recording.png"});
  CAPTURING = true;
}, false);


/*
 * You can trigger this when you want; I am doing it on every mouse move over the video (triggered by the content_script.js)
 */
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (!CAPTURING) {
      console.log('User needs to activate the recording of the screen')
      return false; // no response
    }

    ctx.drawImage(video, 0, 0);
    var url = canvas.toDataURL('image/png');
    window.open(url);
  }
);