简体   繁体   English

在没有getImageData()的情况下从HTML画布获取像素的颜色吗?

[英]Get pixels' colors from HTML Canvas WITHOUT getImageData()?

Task 任务

I am currently trying to create a web extension for Firefox. 我目前正在尝试为Firefox创建Web扩展。 It should be able to read images' pixels. 它应该能够读取图像的像素。 For that purpose, I am rendering the image on an invsible canvas, and then I want to read it. 为此,我将图像渲染在不可见的画布上,然后再阅读。

Example Code 范例程式码

function getImdata(reference) {
    var canvas=document.createElement("canvas");
    canvas.width=reference.naturalWidth;
    canvas.height=reference.naturalHeight;
    var context=canvas.getContext("2d");
    context.drawImage(reference,0,0);
    return context.getImageData(0,0,reference.naturalWidth,reference.naturalHeight); //Here I actually get the error...
}

Problem 问题

However, I am getting a "Security Error" if I use "getImageData()". 但是,如果我使用“ getImageData()”,则会收到“安全错误”。

Question

So I need a workaround, but couldn't find anything myself. 因此,我需要一种解决方法,但自己找不到任何东西。 How can I read images' pixels without getImageData() ? 没有getImageData()的情况下如何读取图像的像素?

EDIT 编辑

Apparently it has something to do with CORS : HTML5 Canvas getImageData and Same Origin Policy 显然,它与CORS有关: HTML5 Canvas getImageData和同源策略

Thanks in advance! 提前致谢!

There is. 有。 Since you're running from an extension your extension will have privileged access to cross-origin sources but only if loaded via fetch() and XMLHttpRequest() from a content script (or background script) - excerpt from that link: 由于您是通过扩展程序运行的,因此您的扩展程序将有权访问跨域源,但是只有通过内容脚本 (或背景脚本)中的fetch()XMLHttpRequest()加载时 ,该链接才会摘录:

Content scripts get the same cross-domain privileges as the rest of the extension: so if the extension has requested cross-domain access for a domain using the permissions key in manifest.json, then its content scripts get access that domain as well. 内容脚本与扩展的其余部分获得相同的跨域特权:因此,如果扩展已使用manifest.json中的权限密钥请求跨域访问域,则其内容脚本也将访问该域。

This is accomplished by exposing more privileged XHR and fetch instances in the content script [...] 这是通过在内容脚本中公开更多特权的XHR和获取实例来实现的[...]

Please note that these calls when called from a content script will not set origin and referer headers which sometimes can cause problems if the cross-origin site expects these to be set - for those cases you will need to use the non-privileged content.XMLHttpRequest or content.fetch() which will bring you back to square one. 请注意,从内容脚本调用时这些调用不会设置originreferer标头,如果跨源站点希望设置这些标头,则有时可能会导致问题-在这种情况下,您将需要使用非特权内容content.XMLHttpRequestcontent.fetch() ,它将带您回到第一个平方。

The permissions in the manifest file (or if set permissions dynamically) must also allow access to these cross-origin sites. 清单文件中的权限(或如果动态设置权限)还必须允许访问这些跨源站点。

This means however that you will have to "reload" the image source separately via these calls. 但是,这意味着您将必须通过这些调用分别“重新加载”图像源。 You can do this the following way by first obtaining the original URL to the image you want to load, say, from a content script : 您可以通过以下方式执行此操作:首先从内容脚本获取要加载的图像的原始URL,例如:

// example loading all images in current tab
let images = document.querySelectorAll("img");
for(let image of images) loadAsBitmap(image.src); // some sub-call using the url

Then load that source via the content script's fetch() : 然后通过内容脚本的fetch()加载该源:

fetch(src).then(resp => {  // load from original source
  return resp.blob();      // obtain a blob
}).then(blob => {          // convert blob, see below
  // ...
};

When the blob is obtained you can convert it to an Object-URL and set that as source for an image and be able to go around the cross-origin restriction we otherwise face. 获得Blob后,您可以将其转换为Object-URL并将其设置为图像的来源,并且可以绕过否则会遇到的跨域限制。 In the content script, next steps would be: 在内容脚本中,下一步将是:

let url = URL.createObjectURL(blob);         // attach Object-URL to blob
let img = new Image();                       // create image element *
img.onload = () => {                         // attach handler
  let c = document.createElement("canvas");  // create canvas
  let ctx = c.getContext("2d");              // get context
  c.width = img.width;                       // canvas size = image
  c.height = img.height;
  ctx.drawImage(img, 0, 0);                  // draw in image
  URL.revokeObjectURL(url);                  // remove reference.
  let imageData = 
    ctx.getImageData(0,0,c.width,c.height);  // get image data
  // .. callback to a function that handles the image data
};
img.src = url;                               // start loading blob

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM