【问题标题】:Get Image uint8 data without canvas在没有画布的情况下获取 Image uint8 数据
【发布时间】:2018-11-15 21:09:26
【问题描述】:

我有一个用例,我想将图像 uint8 数据传递给网络工作者。 现在我正在使用画布来获取 uint8 图像数据。有没有办法在没有画布的情况下做到这一点。

这是我正在使用的一段代码。

let img = new Image(),
        canvas = document.createElement('canvas'),
        context = canvas.getContext('2d');

img.crossOrigin = 'anonymous';
img.src = someImageUrl;

img.onload = () => {
            canvas.height = this.naturalHeight;
            canvas.width = this.naturalWidth;
            context.drawImage(img, 0, 0);
            const imgData = context.getImageData(0, 0, canvas.width, canvas.height);

            // post this imgData to the worker
            worker.postMessage(imageData);
        };

【问题讨论】:

  • 画布不提供 any 方法来获取图像文件的 Uint8 表示。它得到的是一个 Uint8ClampedArray,其中包含与图像中的像素相对应的 RGBA 通道,但它们并不相同,它们已被计算出来,并且由于 sRGB 引起的预乘的有损方面,没有获得准确值的方法。 (这在canvas fingerprinting 中被利用)虽然有一些方法可以获得文件的 Uint8 表示(标题仍然压缩等)。那么你想要其中的哪一个?
  • @Kaiido 感谢您澄清这一点,我想获得 UInt8ClampedArray 进行处理。

标签: javascript image html5-canvas


【解决方案1】:

在不久的将来,您应该能够从 ImageBitmap 转移到您的 Worker,在那里您将在 OffscreenCanvas 中处理它,它本身并不是一个真正的 HTMLCanvas,但提供一种访问相同上下文方法的方法,即使在 Worker 内部也是如此。

截至今天,只有 Chrome 和 Firefox 开始开发此 API,并且它们仍然隐藏在两者中(Chrome 的“Experimental Web Platforms”和 Firefox 的“gfx.offscreencanvas.enabled”)。
即便如此,只有 Chrome 在那里实现了 2DContext,对于 Firefox,你必须回退到 webgl 上下文,我不太了解,所以我将使用 readPixels em> 给别人。

所以是的,没有 HTMLCanvasElement 也可以做到这一点,但现在......我想你最好保持画布的方式。

if (!window.ImageBitmap || !window.OffscreenCanvas) {
  console.log('Your browser doesn\'t support ImageBitmap or OffscreenCanvas, we should fallback to a normal canvas');
} else {
  var img = new Image();
  img.crossOrigin = 'anonymous';
  img.onload = e => createImageBitmap(img).then(passToWorker);
  img.src = "https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg";


  function passToWorker(bitmap) {
    var blob = new Blob([work.textContent], {
      type: 'application/javascript'
    });
    var worker = new Worker(URL.createObjectURL(blob));
    worker.postMessage(bitmap, [bitmap]);
    worker.onmessage = e => {
      if (e.data instanceof ImageData) {
        console.log('ImageData', e.data.data.length, e.data.data[0]);
      } else {
        console.log(e.data);
      }
    };
  }
}
<script id="work" type="worker-script">
onmessage = function(evt) {
  const bitmap = evt.data;
  try {
    const ctx = new OffscreenCanvas(bitmap.width, bitmap.height).getContext('2d');
    if(!ctx) fallbackToWebGL(bitmap);
    ctx.drawImage(bitmap, 0, 0);
    handleImageData(ctx.getImageData(0, 0, bitmap.width, bitmap.height));
  } catch (e) {
    console.log(e, e.name);
    // FF doesn't even return null...
    if (e.name === 'NS_ERROR_NOT_IMPLEMENTED') {
    	fallbackToWebGL(bitmap);
    }
    else postMessage('come back later');
  }
};

function handleImageData(data) {
  postMessage(data);
}

function fallbackToWebGL(bitmap) {
  postMessage('should fallback to webgl readPixels...');
}
</script>

哦,另一种选择是为自己编写一个解析器,无论您的原始图像是什么格式,然后自己提取 RGBA 通道,但老实说,使用 Canvas 并没有那么糟糕。

【讨论】:

  • 感谢您提供如此明确的答案。但它似乎仍然无法解决问题,因为使用的 api 支持非常有限。使用画布的原因是,我正在获取的图像来自不同的域,而且它们似乎没有实现 cors。所以当我做 image.crossOrigin = "anonymous" 它开始抛出 cors 错误。该团队建议我们不要发送 image.crossOrigin,这样我们就可以加载图像了。当我删除 image.crossOrigin 时,我的画布开始向我抛出错误,说它已被污染。
  • @Anurag92 那么你为什么没有在你的问题中说明这一点,甚至只是简单地询问如何规避这个限制?不过现在为时已晚。而且反正这个问题已经回答过很多次了,很简单的“唯一的办法就是使用代理服务器”,所以不要再问了。 [EDIT] 你与另一只手有联系吗?向他们解释您必须有正确的 Allow-Origin 标头,如果他们不愿意将其设置给任何人,他们也可以仅为您的来源设置它。
猜你喜欢
  • 2012-06-01
  • 2013-05-06
  • 2020-08-25
  • 2012-09-28
  • 2013-10-10
  • 2020-04-13
  • 2018-09-05
  • 2013-01-22
  • 2020-06-11
相关资源
最近更新 更多