A quick way to create an RGB array into an RGBA array in Javascript

The emulator I'm working with internally stores a 1-dimensional framebuffer of RGB values. However, the HTML5 canvas uses RGBA values โ€‹โ€‹when invoking putImageData. To display the framebuffer, I am currently going through an RGB array and creating a new RGBA array in the form similar to this .

It seems suboptimal. Much has been written about how to quickly draw canvases, but I still cannot figure out how to improve application performance. Is there a way to convert this RGB array to RGBA array more quickly? The alpha channel will always be completely opaque. Also, is there a way to interact with the canvas so that it accepts an RGB array, not an RGBA value?

+3
javascript html5-canvas
source share
2 answers

It is impossible to use plain RGB, but the loop in this code could be optimized by removing repetitive calculations, deviations from arrays, etc.

In general, you should not use ctx.getImageData to get the target buffer โ€” you generally donโ€™t care what values โ€‹โ€‹already exist, and ctx.createImageData should be used ctx.createImageData . If at all possible, reuse the same raw buffer for each frame.

However, since you want to pre-set the alpha values โ€‹โ€‹to 0xff (by default they are 0x00 ), and you only need to do this once, it seems that it is much more efficient to just fill the canvas and then extract the raw values โ€‹โ€‹with getImageData .

 ctx.fillStyle = '#ffffff'; // implicit alpha of 1 ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); dest = ctx.getImageData(0, 0).data 

and then for each frame, you can just leave the alpha bytes intact:

 var n = 4 * w * h; var s = 0, d = 0; while (d < n) { dest[d++] = src[s++]; dest[d++] = src[s++]; dest[d++] = src[s++]; d++; // skip the alpha byte } 

You can also experiment with "looping around" (that is, repeating four string blocks several times in a while ), although the results will be different in different browsers.

Since it is very likely that your total number of pixels will be a multiple of four, just repeat the block three more times, and then while will only be evaluated for every four pixel copies.

+4
source share

Both ctx.createImageData and ctx.getImageData will create a buffer, later (get) will be slower, since it must also copy the buffer. This jsperf: http://jsperf.com/drawing-pixels-to-data
confirms that we have a 33% drop in Chrome and 16 times slower in Firefox (FFF seems to copy bytes when a copy of Chrome with 32 or 64 bits moves).

I just remember that you can process typed arrays of different types and even create a view in the buffer (image.data.buffer).
Thus, this can allow you to write bytes 4 to 4.

 var dest = ctx.createImageData(width, height); var dest32 = new Int32Array(dest.data.buffer); var i = 0, j=0, last = 3*width*height; while (i<last) { dest32[j] = src[i]<<24 + src[i+1] << 16 + src[i+2] << 8 + 255; i+=3; j++; } 

In this jsperf test, you will see that writing using 32-bit integers is faster: http://jsperf.com/rgb-to-rgba-conversion-with-typed-arrays note that there is a big problem in these tests : since this test is awfull in terms of garbage creation, the accuracy is as follows. After many more launches, we see that we have about 50% gain when recording 4 versus recording 1.

Edit: it might be worth seeing if reading the source using a DataView will speed up the process. but the input array must be a buffer (or have a buffer property such as Uint8Array). ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays/DataView )

Feel free to update the script with such an attempt.

Edit 2: I don't understand that I restarted the test, and now I will write 4 slower: ??? and after, faster: -------

In any case, you have a great interest in storing the dest32 buffer at hand, and do not create a new one every time, since this test measures the creation of Int32Array, it does not match your use case.

+2
source share

All Articles