同一图像的不同ArrayBuffer(在Worker中创建ImageData问题)

问题描述 投票:0回答:1

我试图在Worker中创建ImageData,只需将图片的URL、宽度和高度发布到Worker中就可以了.为了让它工作,我需要获取图片并得到ArrayBuffer。有了这些,我应该能够创建新的ImageData。

//worker.ts
fetch(e.data.url)
  .then( r => r.arrayBuffer() )
  .then( buffer => {
      console.log(buffer.byteLength); // 4022
      new ImageData((new Uint8ClampedArray(buffer)), e.data.width, e.data.height);
  });

我得到以下错误: 输入的数据字节长度不是(4*宽度)的倍数。

在Chrome浏览器中,我可以将不仅仅是URL,而是之前在主线程中用canvas创建的整个ArrayBuffer发布到Worker中,这样就可以了。

//main thread
const canvas = typeof OffscreenCanvas !== 'undefined' ?
   new OffscreenCanvas(img.width, img.height) :
   document.createElement('canvas'),
   ctx = canvas.getContext('2d');

ctx.drawImage(img, 0, 0, img.width, img.height);
const imageData: ImageData = ctx.getImageData(0, 0, img.width, img.height);
console.log(imageData.data.buffer.byteLength); // 106288

问题是在Firefox中,worker.postMessage()只能处理较小的消息,比如URL,而不是整个ArrayBuffer(序列化和反序列化大消息需要很长时间)。这就是为什么我尝试只发送 URL、高度、宽度,并在 Worker 中获取图片的方法。问题在于Worker中获取的ArrayBuffer--它比在主线程中使用canvas创建的ArrayBuffer小得多(相同的URL,不同的方法,不同的ArrayBuffer)。如果我在Worker中有相同的ArrayBuffer,ImageData就会被创建(不会抛出错误)。

我的问题是我有什么不对的地方,如何在使用fetchaxios等获取图像后创建ImageData。

javascript web-worker arraybuffer imagedata
1个回答
0
投票

一个ImageData代表了绘制时将成为像素的红绿蓝和Alpha值。

另一方面,一个图像文件 必须有元数据. 即使图像是你能发明的最基本的位图格式,它仍然需要至少一个 widthheight 的信息,所以你要获取的文件不仅仅是像素的RGBA通道的值,它是一个二进制数据,需要进行解析,可能是解压,解码,甚至可能有一些颜色的信息。

所以,你要获取的文件不仅仅是像素的RGBA通道的数值,它是一个二进制数据,需要经过解析,可能是解压,解码,甚至可能要进行一些色域处理,才能访问这些RGBA通道。


然而,你认为Firefox做不到这一点的前提是有缺陷的。

不要克隆那个ArrayBuffer。调剂 它,它不需要时间。

const worker_script = document.querySelector( '[type="worker-script"]' );
const worker_content = worker_script.textContent;
const worker_blob = new Blob( [ worker_content ], { type: 'text/javascript' } );
const worker_url = URL.createObjectURL( worker_blob );
const worker = new Worker( worker_url );

let start;
worker.onmessage = e => {
  console.log( e.data );
  console.log( 'it took ' + (performance.now() - start) + 'ms to go from main thread to worker and back to main' );
};

const img = new Image();
img.onload = e => {
  const canvas = document.createElement( 'canvas' );
  canvas.width = img.width;
  canvas.height = img.height;
  const ctx = canvas.getContext( '2d' );
  ctx.drawImage( img, 0, 0, img.width, img.height );
  const imageData= ctx.getImageData( 0, 0, img.width, img.height );
  start = performance.now();
  worker.postMessage(
    imageData,
    [ imageData.data.buffer ] // transfer the ArrayBuffer
  );
};
img.crossOrigin = "anonymous";
img.src = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
<script type="worker-script">
  onmessage = e => {
    const imageData = e.data;
    postMessage(
`worker received a ${ imageData.width } x ${ imageData.height } ImageData,
whose buffer's size is ${ imageData.data.buffer.byteLength }bytes`
    );
  };
</script>
© www.soinside.com 2019 - 2024. All rights reserved.