ImageBitmap 和 ImageData 之间的区别

Difference between ImageBitmap and ImageData

ImageBitmap and ImageData和JavaScript有什么区别?你什么时候想要一个或另一个?

ImageBitmap 包含对位图数据的引用,可以将其传递给 GPU 并直接存储在 GPU 中。

ImageData 持有对 canvas pixel ArrayBuffer 的引用,它本身将原始像素值表示为未预乘的 RGBA 颜色通道值的数组,仅供 CPU 使用。

前者可以由GPU直接绘制,不需要其他操作。后者需要读取(通常使用 alpha 预乘),然后在绘制之前移至 GPU。

将它们复制到 canvas 位图 (a.k.a "painted") 所需的时间不同。

var target = document.getElementById('target');
var ctx = target.getContext("2d");

var imageData = ctx.createImageData(300,150);
var imageBitmap = null;

// fill our ImageData with noise
const data = new Uint32Array(imageData.data.buffer);
for(let i=0; i<data.length; i++) {
  data[i] = Math.random()*0xFFFFFF + 0xFF000000;
}
// initial draw
ctx.putImageData(imageData, 0,0);
// we create our ImageBitmap from the current state
// (=> ~ same bitmap as 'imageData')
createImageBitmap(target).then((bmp)=>{
 imageBitmap = bmp;
  btn.disabled = false;
});


// Benchmark.js playground borrowed from 
// https://jsfiddle.net/533hc71h/

var test1_name = 'ImageData';
function test1()
{
 ctx.putImageData(imageData, 0, 0);
}
var test2_name = 'ImageBitmap';
function test2()
{
 ctx.drawImage(imageBitmap, 0, 0);
}
function teardown()
{
 ctx.clearRect(0,0,target.width,target.height);
}

var cycleResults = document.getElementById('cycleResults');
var result = document.getElementById('result');
var btn = document.getElementById('btn');

// BENCHMARK ====================
btn.onclick = function runTests(){

  btn.setAttribute('disable', true);
 cycleResults.innerHTML = '';
  result.textContent = 'Tests running...';
  
  var suite = new Benchmark.Suite;

  // add tests
  suite
  .add(test1_name || 'test1', test1)
  .add(test2_name || 'test2', test2)
  // add listeners
  .on('cycle', function(event) {
    var result = document.createElement('li');
    result.textContent = String(event.target);
    
    document.getElementById('cycleResults')
     .appendChild(result);
  })
  .on('complete', function() {
    result.textContent = 'Fastest is ' + this.filter('fastest').pluck('name');
    btn.setAttribute('disable', false);
    teardown();
  })
  // run async
  .run({ 'async': true });
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/1.0.0/benchmark.min.js"></script>

<ul id='cycleResults'>

</ul>
<div id="result">

</div>
<br>
<button id="btn" disabled>
Run Tests
</button><br>

<canvas id="target"></canvas>

运行 上面的片段我得到了大约 5K OPS(每秒操作数)用于绘制 ImageData,以及 200K+ 用于 Chrome 上的 ImageBitmap(44K 与 FF 中的 125K)。

但是您不能修改 ImageBitmap,也不能以任何有意义的方式读取其内容。

所以,

  • 如果需要绘制位图,请使用 ImageBitmap。
  • 如果您需要读取/操作图像数据,请使用 ImageData。

请记住,由于 OffscreenCanvas API,现在我们还可以直接在 Worker 中保存 canvas 上下文,这可能也适合您的需求。