How do you convert from ArrayBuffer to byte array in javascript? [duplicate] - javascript

I want to read a binary file in JavaScript that would be gotten through XMLHttpRequest and be able to manipulate that data. From my researching I discovered this method of reading a binary file data into an array
var xhr = new XMLHttpRequest();
xhr.open('GET', '/binary_And_Ascii_File.obj', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
var uInt8Array = new Uint8Array(this.response);
};
How do I convert this binary data array to a human-readable-string?

I'm sure you will find this helpful: http://jsdo.it/tsmallfield/uint8array.
Click on javascript tab.
There will appear the code to convert the Uint8Array in a string. The author shows 2 method:
The first is about creating a view.
The second offsetting bytes.
EDIT: report the code for completeness
var buffer = new ArrayBuffer( res.length ), // res is this.response in your case
view = new Uint8Array( buffer ),
len = view.length,
fromCharCode = String.fromCharCode,
i, s, str;
/**
* 1) 8bitの配列に入れて上位ビットけずる
*/
str = "";
for ( i = len; i--; ) {
view[i] = res[i].charCodeAt(0);
}
for ( i = 0; i < len; ++i ) {
str += fromCharCode( view[i] );
}
/**
* 2) & 0xff で上位ビットけずる
*/
str = "";
for ( i = 0; i < len; ++i ) {
str += fromCharCode( res[i].charCodeAt(0) & 0xff );
}

function load_binary_resource(url) {
var byteArray = [];
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.overrideMimeType('text\/plain; charset=x-user-defined');
req.send(null);
if (req.status != 200) return byteArray;
for (var i = 0; i < req.responseText.length; ++i) {
byteArray.push(req.responseText.charCodeAt(i) & 0xff)
}
return byteArray;
}
See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data for more details

Related

Convert base64 string into byte array through javascript

I want to convert "base64" string into bytes array through the javascript.
I received string from the URL like.
("data:image/jpeg;base64,/9j/4QN6RXhpZgAASUkqAAgAAAAIA)
And i want to convert the string into bytes array. because i need this byte array to send Rest API endpoint. The rest API Content-type=application/octet-stream.
You can use XMLHttpRequest to do the dirty work for you:
var url = document.createElement("canvas").toDataURL(); // some data-uri
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.onload = function() {
// result = ArrayBuffer, from here assign a view to it
if (xhr.status === 200) console.log(new Uint8Array(xhr.response));
};
xhr.send();
It's a little more code than using atob() but all conversion happens internally. It's async too which can help with larger Data-URIs.
In newer browsers (which supports it) you can instead use fetch():
// note: atm not all browsers support these features.
fetch(document.createElement("canvas").toDataURL()) // pass in some data-uri
.then(function(response) {return response.arrayBuffer()})
.then(function(buffer) {
console.log(new Uint8Array(buffer));
});
You can try with the following;
function test(base64StringFromURL)
{
var parts = base64StringFromURL.split(";base64,");
var contentType = parts[0].replace("data:", "");
var base64 = parts[1];
var byteArray = base64ToByteArray(base64);
..
}
function base64ToByteArray(base64String) {
try {
var sliceSize = 1024;
var byteCharacters = atob(base64String);
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return byteArrays;
} catch (e) {
console.log("Couldn't convert to byte array: " + e);
return undefined;
}
}
This would prove to be much short solution.
const byteArray = new Buffer(base64String.replace(/^[\w\d;:\/]+base64\,/g, ''), 'base64');
base64String is the string containing the base 64 string.
byteArray is the array you need.
The regex replacement is optional and is just there to deal with prefix as in the case of dataurl string.

What is the most efficient way to transmit file over HTTP?

I writing a client which have to transmit files to a REST webservice.
I take the File object from the input control, then I use FileReader object to convert it in base64 (String). I noticed that the base64 string weight is 30-40% over the original file size.
If I convert that string in binary size literally explodes, so I was wandering if there is a more efficient way to convert in string this file and send over HTTP.
function toBase64() {
var file = document.querySelector('#base64').files[0];
var reader = new FileReader();
reader.addEventListener("load", function () {
var bin = base64toBin(reader.result);
var base64 = reader.result;
console.log(bin, base64);
});
if (file) {
reader.readAsDataURL(file);
}
}
function base64toBin(data) {
var binArray = []
var datEncode = "";
for (let i=0; i < data.length; i++) {
binArray.push(data[i].charCodeAt(0).toString(2));
}
for (let j=0; j < binArray.length; j++) {
var pad = padding_left(binArray[j], '0', 8);
datEncode += pad + ' ';
}
function padding_left(s, c, n) { if (! s || ! c || s.length >= n) {
return s;
}
var max = (n - s.length)/c.length;
for (var i = 0; i < max; i++) {
s = c + s; } return s;
}
return binArray;
}
Here is a poc:
jsfiddle

Converting arraybuffer to string : Maximum call stack size exceeded

This is my code.
var xhr = new XMLHttpRequest();
xhr.open('GET',window.location.href, true);
xhr.responseType = "arraybuffer";
xhr.onload = function(event) {
debugger;
console.log(" coverting array buffer to string ");
alert(String.fromCharCode.apply(null, new Uint8Array(this.response)));
};
xhr.send();
That request is being made to a PDF URL which is around 3 MB in size. I have read a few threads with same error, Maximum call stack size exceeded, telling me that there must be some recursive call but I do not see any recursive call here. Can anyone help?
I had the same problem and I finally used this code:
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
The error is caused by a limitation in the number of function arguments. See "RangeError: Maximum call stack size exceeded" Why?
Instead of String.fromCharCode.apply(), use e. g. a TextEncoder. See Uint8Array to string in Javascript
this.response.arrayBuffer()
.then((buf) => {
const uint8Array = new Uint8Array(buf);
const data = uint8Array.reduce((acc, i) => acc += String.fromCharCode.apply(null, [i]), '');
return data;
})
Thank you so much Anthony O, you saved my 10 days work.
small modification in my scenario is:
Angular 7 :
/** Convert Uint8Array to string */
private static arrayBufferToBase64( buffer: Uint8Array ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return binary;
}

Convert from byte array to StringBase64

I have an array with bytes and need them to be in StringBase64 and I am using the following:
var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayDigestion)));
console.log('digestionB64_2 .......:' + digestionB64);
with the following result:
digestionB64_2 .......:6d9310a8df39348ef2bbd8a0f04f65bba64180666848526a4c93e86aa69433e7
And I've also used the following code and get the same results no difference whatsoever:
function arrayBufferToString(buffer) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return binary;
}
As I understand Strings in Base 64 must end with an = or == characters
Would it be valid if I add those characters manually at the end or is it valid to have a StringBase64 without them?

Edit and add bytes to binary(uint8array)

I want to add a string and some binaries like 0x00 inside my binary file which I loaded via ajax (to get it as binary)
This is my code until now:
var ajax = new XMLHttpRequest();
ajax.open("GET", "test.bin", true);
ajax.responseType = "arraybuffer";
ajax.onload = function () {
var byteArray = new Uint8Array(ajax.response);
// What can i do?
};
ajax.send();
Well, at last I could resolve it:
var str = 'Injected!!!';
var injAr = [0x21,0xFE,str.length];
for (var i = 0; i < str.length; i++) { injAr.push(str.charCodeAt(i));}
injAr.push(0x00,0x3B);
var ajax = new XMLHttpRequest();
ajax.open("GET", "test.gif", true);
ajax.responseType = "arraybuffer";
ajax.onload = function () {
var bAr = new Uint8Array(ajax.response), len = bAr.length - 1;
window.newBAr = new Uint8Array(len + injAr.length);
for (var i = 0; i < len; i++) { newBAr[i] = bAr[i];}
for (var i = 0; i < injAr.length; i++) { newBAr[len + i] = injAr[i];}
}
ajax.send();
Well, this was intended to add comments blocks to a gif correctly, but it can be use also with jpgs, pngs, for example to modify or add exif metadata
You will need to have the reqponse in a format that the javascript will be able to pull out the bytes that are the string and seperate the bytes that are part of the binary. You can do this by positioning the string at the beginning or end with a distinctive byte flag to signify the boundary. I would put the string at the beginning with the flag at the end of it to signify the beginning of the binary since I am unsure of the binary file.
Once you have it seperated, you will need to convert the bytes to numbers and then convert the numbers to characters. Here is a question that goes over how to convert binary to characters.

Categories

Resources