Shadow43375
Shadow43375

Reputation: 604

How to create a blob containing an arbitrary octet in Javascript

I am trying to understand how the Blob object can be used to programmatically create binary files on a byte by byte level in client-side javascript. As a way of building up my know how I am trying to create a single byte blob that contains the following octet: 00000001. Simple right? Unfortunately, I haven't been able to figure out how to do so. Below is the first iteration of my code:

let downloadButton = document.getElementById('downloadButton');
downloadButton.addEventListener('click', function(){
  var myBlob = new Blob([1], {type : "octet/stream"});
  url = window.URL.createObjectURL(myBlob);
  let a = document.createElement('A');
  a.href = url;
  a.download = "testFileOctet";
  a.click();
});

I'm not surprised that this doesn't produce the desired bit sequence '00000001' when viewed in a hex editor. I am however surprised that it outputs 00110001 which is the UTF-8 character encoding of '1'. I know that because javascript is weakly typed all numbers are represented as 64-bit floating points so I would have understood if I had a large 64-bit sequence. Or I would have understood if I had specified the MIME type as 'text/plain' instead of 'octet/stream' and had gotten the UTF-8 encoding output.

As it stands, however, I am at a loss... I even attempted some variations where I changed the array being fed into the Blob constructor. Instead of [1] I tried [0x1]. Same result. I tried [0b00000001]. Same result.

So. What am I doing wrong and how is byte-level file creation possible in client-side javascript? Is this a problem with the way I am using the Blob constructor or is it perhaps something to do with the URL encoding that I am using to get the Blob out of the browser? Any help would be much appreciated

Upvotes: 0

Views: 1785

Answers (1)

Kaiido
Kaiido

Reputation: 136736

The Blob() constructor expects a possibly mixed list of Blob-parts, ArrayBuffer or USVStrings.

  • Blob-parts are other Blob objects.
  • ArrayBuffer are either ArrayBuffer objects, or the .buffer property of a TypedArray you would pass in the list.
  • USVStrings are more like UTF-8 Strings.

In your case, new Blob([1]) , the Number 1, being neither a Blob, nor an ArrayBuffer or TypedArray will get coerced to the USVString "1".

Just like if you did call new Blob([{}]), then the literal object would get coerced to the USVString "[object Object]".

const obj = new Blob([{}]);
new Response(obj).text().then(v=>console.log('obj', v));

const one = new Blob([1]);
new Response(one).text().then(v=>console.log('one', v));

So how do we set arbitrary bytes?

We use an ArrayBuffer and different views over it.

const buf = new ArrayBuffer(1);
const view = new Uint8Array(buf);
view[0] = 1;
const blob = new Blob([buf]);
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'one.bin';
document.body.append(a);
a.click();

Upvotes: 2

Related Questions