Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between ImageBitmap and ImageData

What is the difference between ImageBitmap and ImageData in JavaScript? when do you want the one or the other?

like image 244
Endless Avatar asked Feb 02 '20 23:02

Endless


People also ask

What is ImageBitmap?

The ImageBitmap interface represents a bitmap image which can be drawn to a <canvas> without undue latency. It can be created from a variety of source objects using the createImageBitmap() factory method. ImageBitmap provides an asynchronous and resource efficient pathway to prepare textures for rendering in WebGL.

What is ImageData?

The ImageData interface represents the underlying pixel data of an area of a <canvas> element. It is created using the ImageData() constructor or creator methods on the CanvasRenderingContext2D object associated with a canvas: createImageData() and getImageData() .

How do you get pixels on canvas?

To get the pixel of any specific portion from HTML canvas you can use the HTML canvas getImageData() Method. The getImageData() method usually returns an ImageData object that contains the pixel information of the specified object on the HTML canvas.

How do I get image data from canvas?

The getImageData() method returns an ImageData object that copies the pixel data for the specified rectangle on a canvas. Note: The ImageData object is not a picture, it specifies a part (rectangle) on the canvas, and holds information of every pixel inside that rectangle.


1 Answers

An ImageBitmap holds a reference to bitmap data, which can be passed to and stored directly in the GPU.

An ImageData holds a reference to a canvas pixel ArrayBuffer, which itself represents raw pixel values as an Array of un-premultiplied RGBA color channel values, which is only used by the CPU.

The former can be painted directly by the GPU, with no other operations required. The latter needs to be read (often with alpha pre-multiplication) then moved to the GPU before it can be painted.

They will not take the same amount of time to get copied to the canvas bitmap (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>

Running the above snippet I get around 5K OPS (Operations Per Seconds) for drawing the ImageData, and 200K+ for the ImageBitmap on Chrome (44K vs 125K in FF).

However you can't modify an ImageBitmap, nor read its content in any meaningful way.

So,

  • If you need to draw a Bitmap, use an ImageBitmap.
  • If you need to read / manipulate the image's data, then use an ImageData.

And remember that now we also have means to hold canvas contexts directly in a Worker thanks to the OffscreenCanvas API, might suit your needs too.

like image 71
Kaiido Avatar answered Sep 24 '22 07:09

Kaiido