【问题标题】:Tainted "OffscreenCanvas" may not be exported受污染的“OffscreenCanvas”可能无法导出
【发布时间】:2020-06-08 17:32:27
【问题描述】:

我将 ImageBitmap 传递给 webworker,在画布上呈现,然后生成一个 URL 以加载到主线程上的 THREE.js。

在主线程中

 this.canvas = this.canvasEl.transferControlToOffscreen() 
this.workerInstance.postMessage({canvas: this.canvas}, [this.canvas]);
...

createImageBitmap(this.img).then(imageData =>  {
        this.imageBitmap = imageData
        this.workerInstance.postMessage({image:imageData}, [imageData])

在工人中

_ctx.drawImage(image, 0, 0)
    _canvas.convertToBlob({type: "image/png"}).then(blob => console.log(blob))

DOMException:无法在“OffscreenCanvas”上执行“convertToBlob”: 可能无法导出受污染的“OffscreenCanvas”。

主线程上的图像有crossorigin="anonymous"。它也确实复制了另一个图像,但这是同一个域。

图像是动态创建的:

docString = '<svg width="' + this.width + '" height="' + this.height + '" xmlns="http://www.w3.org/2000/svg"><defs><style type="text/css"><![CDATA[a[href]{color:#0000EE;text-decoration:underline;}' + this.cssembed.join('') + ']]></style></defs><foreignObject x="0" y="0" width="' + this.width + '" height="' + this.height + '">' + parent[0] + docString + parent[1] + '</foreignObject></svg>';
this.img.src = "data:image/svg+xml;utf8," + encodeURIComponent(docString);

代码在这里https://github.com/supereggbert/aframe-htmlembed-component/blob/master/src/htmlcanvas.js

我正在更新它以使用 Offscreen canvas 和 web workers 来加快渲染速度

【问题讨论】:

  • 你有没有在没有跨域的情况下加载该图像?可能是缓存问题,请参阅stackoverflow.com/questions/49503171/… 无论如何,我们需要看看您是如何加载该图像的,因为作为跨域加载的图像不应该污染您的画布,并且具有 crossorigin 属性的图像但是根本不应该加载服务器未正确提供的服务(因此会使 createImageBitmap 抛出)。另外,如果您只是尝试使用 inscreen 画布的 2D 上下文会怎样?
  • 啊...一个带有foreignObject的svg...这是一个非常重要的信息,它与跨域数据无关,正如您所说,您确实生成了该图像。 There was this 前段时间我写过,但看来你已经在使用解决方法了,也许他们对 ImageBitmap 做了什么坏事,我会检查一下。

标签: javascript canvas three.js


【解决方案1】:

这是this known bug 的扩展,我已经给出了explanation here

对于您的情况,似乎即使使用“data:URL hack-around”也不起作用,可能是因为在createImageBitmap 内部步骤中执行了一些其他检查。

我将在错误报告中添加对此的评论,但目前,您必须先在 上光栅化该 svg 图像并将该 用作源对于 ImageBitmap,我想这对于您的情况来说并不理想。

if( !window.OffscreenCanvasRenderingContext2D ) {
  console.warn("Your browser doesn't support the 2D context of the OffscreenCanvas API");
}

const worker = initWorker();

const data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
  '<foreignObject width="100%" height="100%">' +
  '<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
  '<em>I</em> like ' +
  '<span style="color:white; text-shadow:0 0 2px blue;">' +
  'beer</span>' +
  '</div>' +
  '</foreignObject>' +
'</svg>';
const img = new Image();
var url = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(data);

img.onload = function() {
  // create a new canvas just to rasterize that svg
  const canvas = document.createElement( 'canvas' );
  const ctx = canvas.getContext('2d');
  canvas.width = img.width;
  canvas.height = img.height;
  ctx.drawImage(img, 0, 0);
  // use that canvas as the source for the ImageBitmap
  createImageBitmap(canvas).then(bmp => {
    worker.postMessage( bmp, [bmp] );
  });
};

img.src = url;

function initWorker() {
  const script = `
    let canvas, ctx;
    onmessage = e => {
      if(e.data instanceof ImageBitmap) {
        ctx.drawImage( e.data, 0, 0);
        canvas.convertToBlob().then( blob => {
          self.postMessage( blob );
        });
      }
      else {
        canvas = e.data;
        ctx = canvas.getContext('2d');
      }
    };
`
  const url = URL.createObjectURL(new Blob([script], { type: "application/javascript" }));
  const worker = new Worker(url);
  worker.onmessage = e => console.log('from worker', e.data);
  const offscreen = document.getElementById('canvas').transferControlToOffscreen();
  worker.postMessage(offscreen, [offscreen]);
  return worker;
}
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

但是有一点我还是很不喜欢,因为你应该在它到达工作线程声明之前就已经得到了一个错误

在 'Worker' 上执行 'postMessage' 失败:无法传输非来源干净的 ImageBitmap。

我不知道你的 Chrome 是怎么绕过这一步的......

【讨论】:

  • 这是一个了不起的答案。所以我试图通过在屏幕外处理这些图像而获得的好处不会以这种方式实现吗?即在此处理期间停止 UI 冻结?
  • 确实如此,但无论如何,所有艰苦的工作都是由 createImageBitmap 完成的,因此即使使用光栅图像,您的设置也不会让您赢得任何东西。
猜你喜欢
  • 2020-03-25
  • 2018-04-09
  • 2018-02-11
  • 2014-09-14
  • 2021-02-28
  • 2017-01-02
  • 2016-11-11
  • 2017-01-07
  • 1970-01-01
相关资源
最近更新 更多