2
\$\begingroup\$

I have this code here which varies depending on the system architecture (typed arrays depends on endianness). I'm trying to get a 32bit ARGB data array. I was trying to learn DataView, which has a nice way of dealing with "endian-ness".

Can you please help to revise this to use DataView, while working basically as close to the logic as the code below currently follows?

Documentation on DataView: MDN :: DataView

// Getting pixels as a byte (uint8) array
var imageData = ctx.getImageData(0, 0, can.width, can.height);
var pixels8BitsRGBA = imageData.data;

// Reverting bytes from RGBA to ARGB
var pixels8BitsARGB = new Uint8Array(pixels8BitsRGBA.length + 8); // +8 bytes for the two leading 32 bytes integers
for(var i = 0 ; i < pixels8BitsRGBA.length ; i += 4) {
    pixels8BitsARGB[i+8 ] = pixels8BitsRGBA[i+3];
    pixels8BitsARGB[i+9 ] = pixels8BitsRGBA[i  ];
    pixels8BitsARGB[i+10] = pixels8BitsRGBA[i+1];
    pixels8BitsARGB[i+11] = pixels8BitsRGBA[i+2];
}

// Converting array buffer to a uint32 one, and adding leading width and height
var pixelsAs32Bits = new Uint32Array(pixels8BitsARGB.buffer);
pixelsAs32Bits[0] = can.width;
pixelsAs32Bits[1] = can.height;

console.log(pixelsAs32Bits);
\$\endgroup\$
  • \$\begingroup\$ As far as I can tell, the question of endianness is independent of your current code. Your byte-swapping loop works regardless of endianness; RGBA → ARGB is about the order of bytes, not the bits within them. So unless I'm mistaken, there's no need to use DataView for this. \$\endgroup\$ – Flambino Oct 18 '14 at 19:43
  • \$\begingroup\$ Thanks @Flambino but when we go to 32 bits though the size of the array is the can.width * can.height. when in 8 bit the size of the array is can.width * can.height * 4 and the values in the 32bit array depend on the endianness no? \$\endgroup\$ – Noitidart Oct 18 '14 at 19:54
  • \$\begingroup\$ True, although that still shouldn't change much, as far as I can tell. You create your 32bit buffer straight from the 8bit buffer, so the bytes and their bits will still be in the same order. At least I'd very much hope so. When you read it back out, you'll still want to read 1 byte at a time: A, R, G, and finally B. The numerical representation of an ARGB pixel is dependent on endianness, but the channels themselves should be just fine, I'd think. But I may be wrong; I'm just thinking out loud. \$\endgroup\$ – Flambino Oct 18 '14 at 20:15
  • \$\begingroup\$ Yep you're right the numerical rep is dependent. That's what I'm trying to get straight because I get this data from html5 canvas via javascript then plug it into xorg with js-ctypes. The image comes out all blue like: i.imgur.com/CfrVnOB.png notice on left its all blue, the image on right is original. \$\endgroup\$ – Noitidart Oct 18 '14 at 20:24
  • \$\begingroup\$ Ah, gotcha. Strange. You should add that image, and your intended use (xorg, js-ctypes) to the question by the way. Though, it might actually be a better question for StackOverflow at this point. Your code seems just fine from a review perspective, so now it's more "how do I get the right result?". I think perhaps someone on SO might know a way. \$\endgroup\$ – Flambino Oct 18 '14 at 20:31
3
\$\begingroup\$

Using DataView is pretty much the same thing. Probably slower though. But it allows you to see that you only have to worry about endianness when dealing with values using more than one byte, like you do when storing width and height using 4 unsigned bytes each.

// Getting pixels as a byte (uint8) array
var imageData = ctx.getImageData(0, 0, can.width, can.height);
var pixels8BitsRGBA = imageData.data;

var i;
var pixelsAs32Bits = new Uint32Array(pixels8BitsRGBA.length + 8); // +8 bytes for the two leading UInt32
var pixelsARGB = new DataView(pixelsAs32Bits.buffer);

// Reverting bytes from RGBA to ARGB
pixelsARGB.setUint32(0, can.width, true); // little endian
pixelsARGB.setUint32(4, can.height, true);  // little endian
for(i = 0; i < pixels8BitsRGBA.length ; i += 4) {
    pixelsARGB.setUint8(i + 8, pixels8BitsRGBA[i + 3]);
    pixelsARGB.setUint8(i + 9, pixels8BitsRGBA[i]);
    pixelsARGB.setUint8(i + 10, pixels8BitsRGBA[i + 1]);
    pixelsARGB.setUint8(i + 11, pixels8BitsRGBA[i + 2]);
}

console.log(pixelsAs32Bits);
\$\endgroup\$
  • \$\begingroup\$ Thank you very much for this answer for an old question of mine! This is still an issue for me and it was on hold your reply will help me to get back on it. Thank you very very much! :) \$\endgroup\$ – Noitidart Dec 31 '14 at 10:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.