user125756 user125756 - 3 months ago 11
HTML Question

Canvas using Uint32Array: Wrong colors are being rendered

I'm currently creating a JS canvas where I want to display a box of different colors.

I'm using uint32 for extra speed, and my colors never display correctly!
I've looked at the examples mainly over here: http://stackoverflow.com/a/19502117 where someone said in the comments:


(small I or JS will throw an error). Tip for OP: colors for Uint32 can also be given simply be using hex - no need to do shifting: 0xff00000 = black + alpha set to 255; for little-endian/LSB CPUs, opposite on big-endian/MSB CPUs."


I'm certain my laptop is little-endian.

I have a demo of my issue here: http://jsfiddle.net/GhwUC/357/

var canvas = document.getElementById('canvas');
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);

var buf = new ArrayBuffer(imageData.data.length);
var buf8 = new Uint8ClampedArray(buf);
var data = new Uint32Array(buf);

for (var y = 0; y < canvasHeight; ++y) {
for (var x = 0; x < canvasWidth; ++x) {
data[y * canvasWidth + x] = 0xff80d7ff // Should be light blue (#80d7ff)
}
}

imageData.data.set(buf8);

ctx.putImageData(imageData, 0, 0);


The color in question here is:

color

But the fiddle displays a yellow-ish color:
color fail

It's the same on other colors, thanks a lot in advance!

Answer

This happens when you treat a Uint8Array as a Uint32Array:

var buf = new Uint8Array([0x01, 0x45, 0x89, 0xcd]).buffer;
console.log(new Uint32Array(buf)[0].toString(16)); // "cd894501"

So the order must be AABBGGRR instead of AARRGGBB:

var canvas = document.getElementById('canvas');
var canvasWidth  = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);

var buf = new ArrayBuffer(imageData.data.length);
var buf8 = new Uint8ClampedArray(buf);
var data = new Uint32Array(buf);

for (var y = 0; y < canvasHeight; ++y) {
    for (var x = 0; x < canvasWidth; ++x) {
        var value = x * y & 0xff;
        data[y * canvasWidth + x] = 0xffffd780 // light blue (#80d7ff)
    }
}

imageData.data.set(buf8);
ctx.putImageData(imageData, 0, 0);
<canvas id="canvas" height="256" width="256"></canvas>

Comments