是否可以在不创建b​​lob和URL.createObjectURL的情况下将png / jpeg字节数组呈现给元素?

时间:2019-04-10 08:41:21

标签: javascript angular web

我正在用Angular和grpc-web流编写前端应用程序。目标是以60-100 FPS的速度渲染流中的图像有效负载。它以前是在WPF中实现的,但现在我需要切换到Web前端。我注意到,即使二进制映像已传输到浏览器,我仍然需要创建一个Blob URL进行下载。

我当前的策略是:

URL.revokeObjectURL(this.ImageSrc);
const blob = new Blob([res.getImage_asU8()], {type: res.getType()});
this.ImageSrc = URL.createObjectURL(blob);

但是,存在两个主要的性能问题 1. CPU使用率很高。我使用CDT对其进行了分析,发现new Blob()占用了最多的脚本时间。 2.尽管对象已经在内存中,但是在创建Blob URL之后,img元素似乎又从内存中下载了Blob。通过CDT网络监控,我发现每个内存Blob都需要10到30毫秒才能“下载”。 (更新:可能是由于CDT降低了性能)

除了为Blob创建URL外,我还尝试使用base64渲染图像。图片为800 * 600单色png,在这种情况下,base64不能正常工作。

我想知道是否可以将流传输的二进制图像直接呈现到元素(img,canvas或svg)上而不创建blob或从内存中重新下载blob。谢谢!

4月10日更新

我制作了一个test project来比较图像更新速度。 我打算比较三种使用情况,但是我不知道如何在浏览器JavaScript中将png / jpeg二进制有效地解码为RGBA,所以我跳过了。

多图像比较

<img> + createObjectURL: img + blob

<canvas> + putImageData: canvas

因此,当并行传输10张图像时,图像+ Blob解决方案似乎比基于画布的方法快。

单图比较

<img> + createObjectURL: img + blob

<canvas> + putImageData: server-side + canvas

令人惊讶的是,img可以保持这种速度。画布似乎太重了,无法以这种速度进行更新。

结论

<img> + createObjectURL应该适合大多数FPS较高的情况。 **不要相信CDT中的时间,因为CDT会减慢执行速度**。我在这里没有做非常仔细的比较,如果我没有正确使用canvas元素,请告诉我。此外,只要及时调用<img> + createObjectURLURL.revokeObjectURL的堆使用率就会比使用画布低得多。

2 个答案:

答案 0 :(得分:0)

这实际上取决于图像的来源。

这里最简单的想法是将其作为视频流发送。

如果这不可行,那么您可以考虑将原始位图数据发送为Uint8 [R,G,B,A,R,G,B,A],这样您就可以直接将其推送到画布上,因为您具有固定的宽度和高度。

const width = 300;
const height = 150;
const service = new Worker(getWorkerURL());
const ctx = canvas.getContext('2d');

service.onmessage = e => {
  const img = new ImageData(e.data, 300, 150);
  ctx.putImageData(img,0,0);
};





// fake service
// a simple Worker that will send a message with an Uint8ClampedArray of random data

function getWorkerURL() {
  const content = `
function sendData() {
  const arr = new Uint8ClampedArray(300*150*4);
  for(let i = 0; i<arr.length; i++) {
    if(i%4 === 3) arr[i] = 255;
    arr[i] = Math.random() * 255;
  }
  postMessage(arr, [arr.buffer]);
  if(self.requestAnimationFrame)
    self.requestAnimationFrame(sendData);
  else setTimeout(sendData, 16);
}
sendData();`;
  const blob = new Blob([content], {type: 'application/javascript'});
  return URL.createObjectURL(blob);
}
<canvas id="canvas"></canvas>

如果这也不可能,并且您必须发送二进制编码的图像,那么没有比通过<img>元素更好的方法了,即使确实如此,这也意味着很多异步操作,例如网络操作。 当然,您可以尝试自己从接收到的ArrayBuffer中解析二进制文件,并对原始像素值进行解码,但是我的直言不讳,您将需要做大量的工作才能与内置实现竞争。 / p>

答案 1 :(得分:0)

也许一些的工作可以转移给网络工作者?

例如,createImageBitmap可以从Blob创建ImageBitmap,而ImageBitmap实现了Transferable接口,这意味着它可以在Web Worker和主线程之间进行传输。

那么,也许考虑让一名网络工作者生成ImageBitmap,然后将其传递到主线程并渲染到画布上?