【问题标题】:Different ArrayBuffer for the same image (Creating ImageData in Worker problem)同一图像的不同 ArrayBuffer(在 Worker 中创建 ImageData 问题)
【发布时间】:2020-08-28 05:14:07
【问题描述】:

我试图通过仅将带有图像 URL、宽度和高度的消息发布到 Worker 来在 Worker 内创建 ImageData。 为了使它工作,我需要获取图像并获取 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 发布到 Worker,还可以将之前在主线程中使用画布创建的整个 ArrayBuffer 发布到并且可以正常工作:

//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 - 它比在主线程中使用画布创建的要小得多(相同的 URL,不同的方法,不同的 ArrayBuffer)。如果我在 Worker 中有相同的 ArrayBuffer,就会创建 ImageData(不会抛出错误)。

我的问题是我做错了什么,如何在使用 fetch/axios 等获取图像后创建 ImageData。

【问题讨论】:

    标签: javascript web-worker arraybuffer imagedata


    【解决方案1】:

    ImageData 表示绘制时将成为像素的红绿蓝和 Alpha 值。

    另一方面,图像文件必须有元数据。即使图像是您可以发明的最基本的位图格式,它仍然至少需要widthheight 信息。

    因此,您要获取的文件不仅仅是像素的 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>

    【讨论】:

      猜你喜欢
      • 2016-07-13
      • 1970-01-01
      • 2015-02-15
      • 1970-01-01
      • 1970-01-01
      • 2016-04-22
      • 1970-01-01
      • 2021-07-06
      • 1970-01-01
      相关资源
      最近更新 更多