ImageBitmap和ImageData的区别

18

1
阅读您链接中的第一段文字 - 这就是区别所在 - 当您使用哪一个时,它很简单...哪一个是适当的。 - Jaromanda X
仍然不太理解,两者都是图像的某种表示形式,都可以在画布上绘制,都在使用postmessage发送内容时具有结构克隆功能。那么它们之间的根本区别是什么?“哪一个更合适”这个回答在我看来相当糟糕...我很少使用画布 - 我正在使用套接字构建自己的可克隆算法,并想知道为什么我不能将它们表示为相同的东西... - Endless
它们中哪一个在通过Web Worker传输时会更快?为什么我们甚至有两个接口,而它们基本上是相同的东西? - Endless
1个回答

37

ImageBitmap保存对位图数据的引用,可以直接传递并存储在GPU中。

ImageData保存对canvas像素ArrayBuffer的引用,它本身表示未预乘RGBA颜色通道值的Array作为原始像素值,仅由CPU使用。

前者可以直接由GPU绘制,不需要其他操作。后者需要被读取(通常进行alpha预乘)然后移动到GPU才能绘制。

它们复制到画布位图(也称为“绘制”)所需的时间不同。

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>

运行上述代码片段,我在Chrome中获得了大约5K OPS(每秒操作次数)以绘制ImageData,以及200K+用于ImageBitmap(在FF中为44K vs 125K)。
但是,您不能修改ImageBitmap,也无法以任何有意义的方式读取其内容。
所以,
  • 如果需要绘制位图,请使用ImageBitmap
  • 如果需要读取/操作图像数据,则使用ImageData
并且请记住,现在我们还可以通过OffscreenCanvas API直接在Worker中持有画布上下文,这也可能适合您的需求。

感谢您添加基准测试!有趣的是,在Firefox 109上的差异微不足道,在两种情况下都只有大约20k操作。 - Thomas
@Thomas 是的,Firefox仍然没有正确实现ImageBitmap,他们仍然将其保留在CPU端,而不是真正创建GPU位图。但是,在我的当前机器上,它仍然比putImageData快3倍,我仍然不会认为它是可以忽略不计的。也许您的配置有些东西阻止了GPU的使用。 - Kaiido
然而我必须承认这个测试存在一个问题:它只计算了在 CPU 上花费的时间,而没有计算在作曲家中花费的时间,这可能在另一个线程中(例如在 Chrome 中)。 - Kaiido

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接