简体   繁体   中英

How can I convert an ArrayBuffer to 11-Bits Values and Back again in Javascript

I need to convert a 256-bit ArrayBuffer into 24 11-bit values and then back again.

Is there a simple code snippet to handle this type of operation.

I have this version, to convert it to 24 11 bit values.

var newBuffer = new Uint8Array(data);

var result = [];
for (var i =0, l = 24;i<l;i++){
  var index = parseInt((i*11.0)/8.0);
  var subBuffer;

  if (i==23){
    var proxyBuffer = new Uint8Array(2);
    proxyBuffer.set(newBuffer.slice(index,index+1));
    subBuffer = proxyBuffer;
  }else{
    subBuffer = newBuffer.slice(index,index+2);
  }

  var value = new Uint16Array(subBuffer.buffer);
  value = value >> (i*3)%8;
  value = value % 2048;
  result.push(value);
}
console.log(result);

Using bit operations can simplify the conversion process - using parseInt and decimal arithmetic is not an easy approach.

The concept code below uses plain arrays of octet and 11 bit values. While Uint8Array and Uint16Array types may be a better choice, creating typed arrays and/or converting an arrayBuffer to and from a suitable array type is not included.

 function ui8To11( buffer8) { var buffer11 = []; var acc = 0; var accBits = 0; function add( octet) { acc = (octet << accBits) | acc; accBits += 8; if( accBits >=11) { buffer11.push( acc & 0x7ff); acc >>= 11; accBits -= 11; } } function flush() { if( accBits) { buffer11.push( acc); } } buffer8.forEach( add); flush(); return buffer11; } function ui11To8( buffer11) { var buffer8 = []; var acc = 0; var accBits = 0; function add( ui11) { acc = (ui11 << accBits) | acc; accBits += 11; while( accBits >= 8) { buffer8.push( acc & 0xff); acc >>= 8; accBits -= 8; } } function flush() { if( accBits) { buffer8.push( acc); } } buffer11.forEach( add); flush(); return buffer8; } var buffer8 = [1,2,3]; // 8 bit values, least significant octet at index 0 console.log("octets: ", buffer8); var buffer11 = ui8To11( buffer8); console.log("undectets: ", buffer11); var reconstructed = ui11To8( buffer11) console.log("convertedBack", reconstructed); 

There is an assumption here that the input array is little-endian, as in each entry in the input array is more significant than the previous entry.

Conversion between 8 and 11 bit values and back again follows a similar pattern, but pushing bits from the accumulator to the output array requires a loop when converting from a higher number of bits to a lower.

The example takes 3 x 8 bit values (24 bits in total) and produces 3 x 11 bit values (33 bits in total). Converting back 33 bits to uint8 integers produces 5 x 8 bit values ( 40 bits). You may need to add code to limit the number of integers pushed into output arrays within conversion routines or truncate output arrays returned as required.

There is a library called Uint1Array which makes everything much easier.

var arr = new Uint1Array(buffer);

for (let i=0, l=arr.length; i<l; i+=11){
    var zero = new Uint1Array(16);
    for (let index =0, length = 11; index<length;index++){
        zero[index]=arr[i+index];
    }

    let bit16 = new Uint16Array(zero.buffer)[0];
    outPut.push(bit16);
}

console.log(outPut);

var bit256 = new Uint1Array(256);
for (let i=0, l=outPut.length;i<l;i++){
    var hold = new Uint16Array(1);
    hold[0]=outPut[i];
    let bit16 = new Uint1Array(hold.buffer);
    let bit11 = bit16.slice(0,11);

    for (let i2=0, l2=11;i2<l2;i2++){
        bit256[(i*11)+i2]=bit11[i2];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM